Skip to content

Commit

Permalink
Calling the syntax methods with a block yields the return object. Closes
Browse files Browse the repository at this point in the history
  • Loading branch information
justinko authored and joshuaclayton committed Oct 14, 2011
1 parent f4ee363 commit f32651d
Show file tree
Hide file tree
Showing 7 changed files with 96 additions and 11 deletions.
7 changes: 6 additions & 1 deletion GETTING_STARTED.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,12 @@ factory\_girl supports several different build strategies: build, create, attrib
attrs = FactoryGirl.attributes_for(:user)

# Returns an object with all defined attributes stubbed out
stub = FactoryGirl.build_stubbed(:user)
stub = FactoryGirl.build_stubbed(:user

# Passing a block to any of the methods above will yield the return object
FactoryGirl.create(:user) do |user|
user.posts.create(attributes_for(:post))
end

No matter which strategy is used, it's possible to override the defined attributes by passing a hash:

Expand Down
6 changes: 4 additions & 2 deletions lib/factory_girl/factory.rb
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ def add_callback(name, &block)
@attribute_list.add_callback(Callback.new(name, block))
end

def run(proxy_class, overrides) #:nodoc:
def run(proxy_class, overrides, &block) #:nodoc:
ensure_compiled
proxy = proxy_class.new(build_class)
callbacks.each { |callback| proxy.add_callback(callback) }
Expand All @@ -72,7 +72,9 @@ def run(proxy_class, overrides) #:nodoc:
end
end
overrides.each { |attr, val| proxy.set(attr, val) }
proxy.result(@to_create_block)
result = proxy.result(@to_create_block)

block ? block.call(result) : result
end

def human_names
Expand Down
24 changes: 16 additions & 8 deletions lib/factory_girl/syntax/methods.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,14 @@ module Methods
# The name of the factory that should be used.
# * overrides: +Hash+
# Attributes to overwrite for this set.
# * block:
# Yields the hash of attributes.
#
# Returns: +Hash+
# A set of attributes that can be used to build an instance of the class
# this factory generates.
def attributes_for(name, overrides = {})
FactoryGirl.factory_by_name(name).run(Proxy::AttributesFor, overrides)
def attributes_for(name, overrides = {}, &block)
FactoryGirl.factory_by_name(name).run(Proxy::AttributesFor, overrides, &block)
end

# Generates and returns an instance from this factory. Attributes can be
Expand All @@ -26,12 +28,14 @@ def attributes_for(name, overrides = {})
# The name of the factory that should be used.
# * overrides: +Hash+
# Attributes to overwrite for this instance.
# * block:
# Yields the built instance.
#
# Returns: +Object+
# An instance of the class this factory generates, with generated attributes
# assigned.
def build(name, overrides = {})
FactoryGirl.factory_by_name(name).run(Proxy::Build, overrides)
def build(name, overrides = {}, &block)
FactoryGirl.factory_by_name(name).run(Proxy::Build, overrides, &block)
end

# Generates, saves, and returns an instance from this factory. Attributes can
Expand All @@ -46,12 +50,14 @@ def build(name, overrides = {})
# The name of the factory that should be used.
# * overrides: +Hash+
# Attributes to overwrite for this instance.
# * block:
# Yields the created instance.
#
# Returns: +Object+
# A saved instance of the class this factory generates, with generated
# attributes assigned.
def create(name, overrides = {})
FactoryGirl.factory_by_name(name).run(Proxy::Create, overrides)
def create(name, overrides = {}, &block)
FactoryGirl.factory_by_name(name).run(Proxy::Create, overrides, &block)
end

# Generates and returns an object with all attributes from this factory
Expand All @@ -63,11 +69,13 @@ def create(name, overrides = {})
# The name of the factory that should be used.
# * overrides: +Hash+
# Attributes to overwrite for this instance.
# * block
# Yields the stubbed object.
#
# Returns: +Object+
# An object with generated attributes stubbed out.
def build_stubbed(name, overrides = {})
FactoryGirl.factory_by_name(name).run(Proxy::Stub, overrides)
def build_stubbed(name, overrides = {}, &block)
FactoryGirl.factory_by_name(name).run(Proxy::Stub, overrides, &block)
end

# Builds and returns multiple instances from this factory as an array. Attributes can be
Expand Down
17 changes: 17 additions & 0 deletions spec/acceptance/attributes_for_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,20 @@
end
end

describe "calling `attributes_for` with a block" do
include FactoryGirl::Syntax::Methods

before do
define_model('Company', :name => :string)

FactoryGirl.define do
factory :company
end
end

it "passes the hash of attributes" do
attributes_for(:company, :name => 'thoughtbot') do |attributes|
attributes[:name].should eq('thoughtbot')
end
end
end
17 changes: 17 additions & 0 deletions spec/acceptance/build_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -60,5 +60,22 @@
subject.user.should be_kind_of(User)
subject.user.should be_new_record
end
end

describe "calling `build` with a block" do
include FactoryGirl::Syntax::Methods

before do
define_model('Company', :name => :string)

FactoryGirl.define do
factory :company
end
end

it "passes the built instance" do
build(:company, :name => 'thoughtbot') do |company|
company.name.should eq('thoughtbot')
end
end
end
18 changes: 18 additions & 0 deletions spec/acceptance/build_stubbed_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -75,3 +75,21 @@
end
end

describe "calling `build_stubbed` with a block" do
include FactoryGirl::Syntax::Methods

before do
define_model('Company', :name => :string)

FactoryGirl.define do
factory :company
end
end

it "passes the stub instance" do
build_stubbed(:company, :name => 'thoughtbot') do |company|
company.name.should eq('thoughtbot')
expect { company.save }.to raise_error(RuntimeError)
end
end
end
18 changes: 18 additions & 0 deletions spec/acceptance/create_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -89,3 +89,21 @@ def persisted?
FactoryGirl.create(:user).should be_persisted
end
end

describe "calling `create` with a block" do
include FactoryGirl::Syntax::Methods

before do
define_model('Company', :name => :string)

FactoryGirl.define do
factory :company
end
end

it "passes the created instance" do
create(:company, :name => 'thoughtbot') do |company|
company.name.should eq('thoughtbot')
end
end
end

4 comments on commit f32651d

@yfeldblum
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The specs should also verify that the block was called.

If the block does not get called then the expectation will never be declared because the expectation is declared inside the block. Therefore there should be a separate set specifications that expect the block to be called in the first place.

it "calls the block" do
  block = proc { nil }
  block.should_receive(:call)
  create(:company, :name => 'thoughtbot', &block)
end

This applies to each of #create, #build, #stub, and #attributes_for.

@joshuaclayton
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@yfeldblum the tests do test that the block is called. That's what's allowing the testing of attributes on company in this spec, for example:

create(:company, :name => 'thoughtbot') do |company|
  company.name.should eq('thoughtbot')
end

@joshuaclayton
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nevermind, I see what you're saying now, good catch.

@joshuaclayton
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Commit: 4ede9f1

Please sign in to comment.