Change syntax for ignoring attributes to use block syntax instead of

calling ignore on individual declarations.

Old syntax:

    factory :user do
      rockstar(true).ignore
      four { 2 + 2 }.ignore

      name { "John Doe#{" - Rockstar" if rockstar}" }
    end

New syntax:

    factory :user do
      ignore do
        rockstar true
        four     { 2 + 2 }
      end

      name { "John Doe#{" - Rockstar" if rockstar}" }
    end
This commit is contained in:
Joshua Clayton 2011-10-07 18:19:27 -04:00
parent 481ea09f2d
commit dc32fd69e8
26 changed files with 152 additions and 92 deletions

View File

@ -159,8 +159,10 @@ Transient Attributes
There may be times where your code can be DRYed up by passing in transient attributes to factories.
factory :user do
rockstar(true).ignore
upcased { false }.ignore
ignore do
rockstar true
upcased { false }
end
name { "John Doe#{" - Rockstar" if rockstar}" }
email { "#{name.downcase}@example.com" }

View File

@ -12,16 +12,12 @@ module FactoryGirl
attr_reader :name, :ignored
def initialize(name)
def initialize(name, ignored)
@name = name.to_sym
@ignored = false
@ignored = ignored
ensure_non_attribute_writer!
end
def ignore
@ignored = true
end
def add_to(proxy)
end

View File

@ -4,7 +4,7 @@ module FactoryGirl
attr_reader :factory
def initialize(name, factory, overrides)
super(name)
super(name, false)
@factory = factory
@overrides = overrides
end

View File

@ -1,8 +1,8 @@
module FactoryGirl
class Attribute #:nodoc:
class Dynamic < Attribute #:nodoc:
def initialize(name, block)
super(name)
def initialize(name, ignored, block)
super(name, ignored)
@block = block
end
@ -11,7 +11,12 @@ module FactoryGirl
if FactoryGirl::Sequence === value
raise SequenceAbuseError
end
proxy.set(name, value, @ignored)
if @ignored
proxy.set_ignored(name, value)
else
proxy.set(name, value)
end
end
end
end

View File

@ -2,13 +2,18 @@ module FactoryGirl
class Attribute
class Sequence < Attribute
def initialize(name, sequence)
super(name)
def initialize(name, sequence, ignored)
super(name, ignored)
@sequence = sequence
end
def add_to(proxy)
proxy.set(name, FactoryGirl.generate(@sequence))
value = FactoryGirl.generate(@sequence)
if @ignored
proxy.set_ignored(name, value)
else
proxy.set(name, value)
end
end
end

View File

@ -5,13 +5,17 @@ module FactoryGirl
attr_reader :value
def initialize(name, value)
super(name)
def initialize(name, value, ignored)
super(name, ignored)
@value = value
end
def add_to(proxy)
proxy.set(name, @value, @ignored)
if @ignored
proxy.set_ignored(name, @value)
else
proxy.set(name, @value)
end
end
def priority

View File

@ -2,18 +2,18 @@ module FactoryGirl
class Declaration
attr_reader :name
def initialize(name)
@name = name
def initialize(name, ignored = false)
@name = name
@ignored = ignored
end
def ignore
$stderr.puts "DEPRECATION WARNING: Use ignore block syntax instead of calling #ignore"
@ignored = true
end
def to_attributes
build.tap do |attributes|
attributes.each(&:ignore) if @ignored
end
build
end
end
end

View File

@ -2,7 +2,7 @@ module FactoryGirl
class Declaration
class Association < Declaration
def initialize(name, options)
super(name)
super(name, false)
@options = options
end

View File

@ -1,15 +1,15 @@
module FactoryGirl
class Declaration
class Dynamic < Declaration
def initialize(name, block)
super(name)
def initialize(name, ignored = false, block)
super(name, ignored)
@block = block
end
private
def build
[Attribute::Dynamic.new(name, @block)]
[Attribute::Dynamic.new(name, @ignored, @block)]
end
end
end

View File

@ -1,8 +1,8 @@
module FactoryGirl
class Declaration
class Implicit < Declaration
def initialize(name, factory = nil)
super(name)
def initialize(name, factory = nil, ignored = false)
super(name, ignored)
@factory = factory
end
@ -12,7 +12,7 @@ module FactoryGirl
if FactoryGirl.factories.registered?(name)
[Attribute::Association.new(name, name, {})]
elsif FactoryGirl.sequences.registered?(name)
[Attribute::Sequence.new(name, name)]
[Attribute::Sequence.new(name, name, @ignored)]
else
trait_root = @factory || FactoryGirl
trait_root.trait_by_name(name).attributes.to_a

View File

@ -1,15 +1,15 @@
module FactoryGirl
class Declaration
class Static < Declaration
def initialize(name, value)
super(name)
def initialize(name, value, ignored = false)
super(name, ignored)
@value = value
end
private
def build
[Attribute::Static.new(name, @value)]
[Attribute::Static.new(name, @value, @ignored)]
end
end
end

View File

@ -8,8 +8,9 @@ module FactoryGirl
attr_reader :child_factories
def initialize(factory)
@factory = factory
def initialize(factory, ignore = false)
@factory = factory
@ignore = ignore
@child_factories = []
end
@ -36,16 +37,21 @@ module FactoryGirl
if value
raise AttributeDefinitionError, "Both value and block given"
else
declaration = Declaration::Dynamic.new(name, block)
declaration = Declaration::Dynamic.new(name, @ignore, block)
end
else
declaration = FactoryGirl::Declaration::Static.new(name, value)
declaration = FactoryGirl::Declaration::Static.new(name, value, @ignore)
end
@factory.declare_attribute(declaration)
declaration
end
def ignore(&block)
proxy = DefinitionProxy.new(@factory, true)
proxy.instance_eval(&block)
end
# Calls add_attribute using the missing method name as the name of the
# attribute, so that:
#
@ -79,7 +85,7 @@ module FactoryGirl
# are equivalent.
def method_missing(name, *args, &block)
if args.empty? && block.nil?
@factory.declare_attribute(Declaration::Implicit.new(name, @factory))
@factory.declare_attribute(Declaration::Implicit.new(name, @factory, @ignore))
elsif args.first.is_a?(Hash) && args.first.has_key?(:factory)
association(name, *args)
else

View File

@ -60,7 +60,15 @@ module FactoryGirl
if factory_overrides.empty?
attribute.add_to(proxy)
else
factory_overrides.each { |attr, val| proxy.set(attr, val, attribute.ignored); overrides.delete(attr) }
factory_overrides.each do |attr, val|
if attribute.ignored
proxy.set_ignored(attr, val)
else
proxy.set(attr, val)
end
overrides.delete(attr)
end
end
end
overrides.each { |attr, val| proxy.set(attr, val) }

View File

@ -5,12 +5,17 @@ module FactoryGirl
def initialize(klass)
@callbacks = {}
@ignored_attributes = {}
end
def get(attribute)
end
def set(attribute, value, ignored = false)
def set(attribute, value)
end
def set_ignored(attribute, value)
@ignored_attributes[attribute] = value
end
def associate(name, factory, attributes)

View File

@ -11,12 +11,8 @@ module FactoryGirl
@ignored_attributes[attribute] || @hash[attribute]
end
def set(attribute, value, ignored = false)
if ignored
@ignored_attributes[attribute] = value
else
@hash[attribute] = value
end
def set(attribute, value)
@hash[attribute] = value
end
def result(to_create)

View File

@ -4,7 +4,6 @@ module FactoryGirl
def initialize(klass)
super(klass)
@instance = klass.new
@ignored_attributes = {}
end
def get(attribute)
@ -15,12 +14,8 @@ module FactoryGirl
end
end
def set(attribute, value, ignored = false)
if ignored
@ignored_attributes[attribute] = value
else
@instance.send(:"#{attribute}=", value)
end
def set(attribute, value)
@instance.send(:"#{attribute}=", value)
end
def associate(name, factory_name, overrides)

View File

@ -55,12 +55,8 @@ module FactoryGirl
end
end
def set(attribute, value, ignored = false)
if ignored
@ignored_attributes[attribute] = value
else
@instance.send(:"#{attribute}=", value)
end
def set(attribute, value)
@instance.send(:"#{attribute}=", value)
end
def associate(name, factory_name, overrides)

View File

@ -8,9 +8,11 @@ describe "transient attributes" do
sequence(:name) {|n| "John #{n}" }
factory :user do
four { 2 + 2 }.ignore
rockstar(true).ignore
upcased(false).ignore
ignore do
four { 2 + 2 }
rockstar true
upcased false
end
name { "#{FactoryGirl.generate(:name)}#{" - Rockstar" if rockstar}" }
email { "#{name.downcase}#{four}@example.com" }
@ -66,3 +68,43 @@ describe "transient attributes" do
end
end
end
describe "deprecated way of ignoring attributes" do
before do
define_model("User", :name => :string)
FactoryGirl.define do
factory :user do
rockstar(false).ignore
name { "John Doe#{" Rockstar" if rockstar}" }
end
end
end
it "assigns attributes correctly" do
FactoryGirl.build(:user, :rockstar => true).name.should == "John Doe Rockstar"
FactoryGirl.build(:user).name.should == "John Doe"
end
end
describe "transient sequences" do
before do
define_model("User", :name => :string)
FactoryGirl.define do
factory :user do
ignore do
sequence(:counter)
end
name { "John Doe #{counter}" }
end
end
end
it "increments sequences correctly" do
FactoryGirl.build(:user).name.should == "John Doe 1"
FactoryGirl.build(:user).name.should == "John Doe 2"
end
end

View File

@ -5,7 +5,7 @@ describe FactoryGirl::Attribute::Dynamic do
let(:proxy) { stub("proxy", :set => nil) }
let(:block) { lambda { } }
subject { FactoryGirl::Attribute::Dynamic.new(name, block) }
subject { FactoryGirl::Attribute::Dynamic.new(name, false, block) }
its(:name) { should == name }
@ -14,7 +14,7 @@ describe FactoryGirl::Attribute::Dynamic do
it "calls the block to set a value" do
subject.add_to(proxy)
proxy.should have_received(:set).with(name, "value", false)
proxy.should have_received(:set).with(name, "value")
end
end
@ -23,7 +23,7 @@ describe FactoryGirl::Attribute::Dynamic do
it "yields the proxy to the block" do
subject.add_to(proxy)
proxy.should have_received(:set).with(name, proxy, false)
proxy.should have_received(:set).with(name, proxy)
end
end
@ -37,7 +37,7 @@ describe FactoryGirl::Attribute::Dynamic do
it "evaluates the attribute from the proxy" do
subject.add_to(proxy)
proxy.should have_received(:set).with(name, result, false)
proxy.should have_received(:set).with(name, result)
end
end
@ -51,6 +51,6 @@ describe FactoryGirl::Attribute::Dynamic do
end
describe FactoryGirl::Attribute::Dynamic, "with a string name" do
subject { FactoryGirl::Attribute::Dynamic.new("name", nil) }
subject { FactoryGirl::Attribute::Dynamic.new("name", nil, false) }
its(:name) { should == :name }
end

View File

@ -6,7 +6,7 @@ describe FactoryGirl::Attribute::Sequence do
let(:sequence) { FactoryGirl::Sequence.new(sequence_name, 5) { |n| "Name #{n}" } }
let(:proxy) { stub("proxy") }
subject { FactoryGirl::Attribute::Sequence.new(name, sequence_name) }
subject { FactoryGirl::Attribute::Sequence.new(name, sequence_name, false) }
before { FactoryGirl.register_sequence(sequence) }
its(:name) { should == name }

View File

@ -5,18 +5,18 @@ describe FactoryGirl::Attribute::Static do
let(:value) { "John" }
let(:proxy) { stub("proxy") }
subject { FactoryGirl::Attribute::Static.new(name, value) }
subject { FactoryGirl::Attribute::Static.new(name, value, false) }
its(:name) { should == name }
it "sets its static value on a proxy" do
proxy.stubs(:set)
subject.add_to(proxy)
proxy.should have_received(:set).with(name, value, false)
proxy.should have_received(:set).with(name, value)
end
end
describe FactoryGirl::Attribute::Static, "with a string name" do
subject { FactoryGirl::Attribute::Static.new("name", nil) }
subject { FactoryGirl::Attribute::Static.new("name", nil, false) }
its(:name) { should == :name }
end

View File

@ -10,8 +10,8 @@ describe FactoryGirl::AttributeList, "overridable" do
end
describe FactoryGirl::AttributeList, "#define_attribute" do
let(:static_attribute) { FactoryGirl::Attribute::Static.new(:full_name, "value") }
let(:dynamic_attribute) { FactoryGirl::Attribute::Dynamic.new(:email, lambda {|u| "#{u.full_name}@example.com" }) }
let(:static_attribute) { FactoryGirl::Attribute::Static.new(:full_name, "value", false) }
let(:dynamic_attribute) { FactoryGirl::Attribute::Dynamic.new(:email, false, lambda {|u| "#{u.full_name}@example.com" }) }
it "maintains a list of attributes" do
subject.define_attribute(static_attribute)
@ -33,7 +33,7 @@ describe FactoryGirl::AttributeList, "#define_attribute" do
end
context "when set as overridable" do
let(:static_attribute_with_same_name) { FactoryGirl::Attribute::Static.new(:full_name, "overridden value") }
let(:static_attribute_with_same_name) { FactoryGirl::Attribute::Static.new(:full_name, "overridden value", false) }
before { subject.overridable }
it "redefines the attribute if the name already exists" do
@ -58,10 +58,10 @@ describe FactoryGirl::AttributeList, "#add_callback" do
end
describe FactoryGirl::AttributeList, "#apply_attributes" do
let(:full_name_attribute) { FactoryGirl::Attribute::Static.new(:full_name, "John Adams") }
let(:city_attribute) { FactoryGirl::Attribute::Static.new(:city, "Boston") }
let(:email_attribute) { FactoryGirl::Attribute::Dynamic.new(:email, lambda {|model| "#{model.full_name}@example.com" }) }
let(:login_attribute) { FactoryGirl::Attribute::Dynamic.new(:login, lambda {|model| "username-#{model.full_name}" }) }
let(:full_name_attribute) { FactoryGirl::Attribute::Static.new(:full_name, "John Adams", false) }
let(:city_attribute) { FactoryGirl::Attribute::Static.new(:city, "Boston", false) }
let(:email_attribute) { FactoryGirl::Attribute::Dynamic.new(:email, false, lambda {|model| "#{model.full_name}@example.com" }) }
let(:login_attribute) { FactoryGirl::Attribute::Dynamic.new(:login, false, lambda {|model| "username-#{model.full_name}" }) }
def list(*attributes)
FactoryGirl::AttributeList.new.tap do |list|
@ -90,7 +90,7 @@ describe FactoryGirl::AttributeList, "#apply_attributes" do
it "doesn't overwrite attributes that are already defined" do
subject.define_attribute(full_name_attribute)
attribute_with_same_name = FactoryGirl::Attribute::Static.new(:full_name, "Benjamin Franklin")
attribute_with_same_name = FactoryGirl::Attribute::Static.new(:full_name, "Benjamin Franklin", false)
subject.apply_attributes(list(attribute_with_same_name))
subject.to_a.should == [full_name_attribute]
@ -120,7 +120,7 @@ describe FactoryGirl::AttributeList, "#apply_attributes" do
it "overwrites attributes that are already defined" do
subject.define_attribute(full_name_attribute)
attribute_with_same_name = FactoryGirl::Attribute::Static.new(:full_name, "Benjamin Franklin")
attribute_with_same_name = FactoryGirl::Attribute::Static.new(:full_name, "Benjamin Franklin", false)
subject.apply_attributes(list(attribute_with_same_name))
subject.to_a.should == [attribute_with_same_name]

View File

@ -3,7 +3,7 @@ require 'spec_helper'
describe FactoryGirl::Attribute do
let(:name) { "user" }
let(:proxy) { stub("proxy") }
subject { FactoryGirl::Attribute.new(name) }
subject { FactoryGirl::Attribute.new(name, false) }
its(:name) { should == name.to_sym }
it { should_not be_association }
@ -17,7 +17,7 @@ describe FactoryGirl::Attribute do
it "raises an error when defining an attribute writer" do
error_message = %{factory_girl uses 'f.test value' syntax rather than 'f.test = value'}
expect {
FactoryGirl::Attribute.new('test=')
FactoryGirl::Attribute.new('test=', false)
}.to raise_error(FactoryGirl::AttributeDefinitionError, error_message)
end
@ -26,7 +26,7 @@ describe FactoryGirl::Attribute do
end
it "uses priority to perform comparisons" do
second_attribute = FactoryGirl::Attribute.new('name')
second_attribute = FactoryGirl::Attribute.new('name', false)
(subject <=> second_attribute).should be_zero
end
end

View File

@ -11,7 +11,7 @@ describe FactoryGirl::DefinitionProxy do
subject.add_attribute(:name, 'value')
factory.ensure_compiled
factory.should have_received(:define_attribute).with(attribute)
FactoryGirl::Attribute::Static.should have_received(:new).with(:name, "value")
FactoryGirl::Attribute::Static.should have_received(:new).with(:name, "value", false)
end
it "should add a dynamic attribute when an attribute is defined with a block" do
@ -21,7 +21,7 @@ describe FactoryGirl::DefinitionProxy do
factory.stubs(:define_attribute)
subject.add_attribute(:name, &block)
factory.ensure_compiled
FactoryGirl::Attribute::Dynamic.should have_received(:new).with(:name, block)
FactoryGirl::Attribute::Dynamic.should have_received(:new).with(:name, false, block)
factory.should have_received(:define_attribute).with(attribute)
end
@ -105,14 +105,14 @@ describe FactoryGirl::DefinitionProxy, "adding attributes" do
it "creates a dynamic attribute" do
subject.add_attribute(attribute_name, &block)
factory.ensure_compiled
FactoryGirl::Attribute::Dynamic.should have_received(:new).with(attribute_name, block)
FactoryGirl::Attribute::Dynamic.should have_received(:new).with(attribute_name, false, block)
factory.should have_received(:define_attribute).with(attribute)
end
it "creates a dynamic attribute without the method being defined" do
subject.send(attribute_name, &block)
factory.ensure_compiled
FactoryGirl::Attribute::Dynamic.should have_received(:new).with(attribute_name, block)
FactoryGirl::Attribute::Dynamic.should have_received(:new).with(attribute_name, false, block)
factory.should have_received(:define_attribute).with(attribute)
end
end
@ -123,14 +123,14 @@ describe FactoryGirl::DefinitionProxy, "adding attributes" do
it "creates a static attribute" do
subject.add_attribute(attribute_name, attribute_value)
factory.ensure_compiled
FactoryGirl::Attribute::Static.should have_received(:new).with(attribute_name, attribute_value)
FactoryGirl::Attribute::Static.should have_received(:new).with(attribute_name, attribute_value, false)
factory.should have_received(:define_attribute).with(attribute)
end
it "creates a static attribute without the method being defined" do
subject.send(attribute_name, attribute_value)
factory.ensure_compiled
FactoryGirl::Attribute::Static.should have_received(:new).with(attribute_name, attribute_value)
FactoryGirl::Attribute::Static.should have_received(:new).with(attribute_name, attribute_value, false)
factory.should have_received(:define_attribute).with(attribute)
end
end

View File

@ -246,8 +246,8 @@ end
describe FactoryGirl::Factory, "running a factory" do
subject { FactoryGirl::Factory.new(:user) }
let(:attribute) { FactoryGirl::Attribute::Static.new(:name, "value") }
let(:declaration) { FactoryGirl::Declaration::Static.new(:name, "value") }
let(:attribute) { FactoryGirl::Attribute::Static.new(:name, "value", false) }
let(:declaration) { FactoryGirl::Declaration::Static.new(:name, "value", false) }
let(:proxy) { stub("proxy", :result => "result", :set => nil) }
let(:attributes) { [attribute] }
let(:attribute_list) { stub('attribute-list', :declarations => [declaration], :to_a => attributes) }

View File

@ -94,7 +94,7 @@ shared_examples_for "proxy with standard getters and setters" do |attribute, val
describe "when setting an ignored attribute" do
before do
subject.set(attribute, value, true)
subject.set_ignored(attribute, value)
end
it { instance.should have_received(:"#{attribute}=").with(value).never }