mirror of
https://github.com/thoughtbot/factory_bot.git
synced 2022-11-09 11:43:51 -05:00
Factory evaluators use inheritance
This commit is contained in:
parent
ac1df1da3b
commit
f2e41389ea
7 changed files with 61 additions and 14 deletions
|
@ -2,10 +2,10 @@ require "active_support/basic_object"
|
|||
|
||||
module FactoryGirl
|
||||
class AttributeAssigner
|
||||
def initialize(build_class, evaluator, attribute_list)
|
||||
def initialize(build_class, evaluator)
|
||||
@build_class = build_class
|
||||
@evaluator = evaluator
|
||||
@attribute_list = attribute_list
|
||||
@attribute_list = evaluator.class.attribute_list
|
||||
@attribute_names_assigned = []
|
||||
end
|
||||
|
||||
|
|
|
@ -1,13 +1,24 @@
|
|||
require "active_support/core_ext/class/attribute"
|
||||
|
||||
module FactoryGirl
|
||||
class Evaluator
|
||||
class_attribute :callbacks, :attribute_lists
|
||||
|
||||
def self.attribute_list
|
||||
AttributeList.new.tap do |list|
|
||||
attribute_lists.each do |attribute_list|
|
||||
list.apply_attributes attribute_list.to_a
|
||||
end
|
||||
end
|
||||
end
|
||||
undef_method(:id) if method_defined?(:id)
|
||||
|
||||
def initialize(build_strategy, overrides = {}, callbacks = [])
|
||||
def initialize(build_strategy, overrides = {})
|
||||
@build_strategy = build_strategy
|
||||
@overrides = overrides
|
||||
@cached_attributes = overrides
|
||||
|
||||
@build_strategy.add_observer(CallbackRunner.new(callbacks, self))
|
||||
@build_strategy.add_observer(CallbackRunner.new(self.class.callbacks, self))
|
||||
end
|
||||
|
||||
delegate :association, :to => :@build_strategy
|
||||
|
|
|
@ -1,13 +1,22 @@
|
|||
module FactoryGirl
|
||||
class EvaluatorClassDefiner
|
||||
def initialize(attributes)
|
||||
def initialize(attributes, callbacks, parent_class)
|
||||
@parent_class = parent_class
|
||||
@callbacks = callbacks
|
||||
@attributes = attributes
|
||||
|
||||
attributes.each do |attribute|
|
||||
define_attribute(attribute.name, attribute.to_proc)
|
||||
end
|
||||
end
|
||||
|
||||
def evaluator_class
|
||||
@evaluator_class ||= Class.new(FactoryGirl::Evaluator)
|
||||
@evaluator_class ||= Class.new(@parent_class).tap do |klass|
|
||||
klass.callbacks ||= []
|
||||
klass.callbacks += @callbacks
|
||||
klass.attribute_lists ||= []
|
||||
klass.attribute_lists += [@attributes]
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
|
|
@ -40,8 +40,8 @@ module FactoryGirl
|
|||
|
||||
proxy = proxy_class.new
|
||||
|
||||
evaluator = evaluator_class_definer.evaluator_class.new(proxy, overrides.symbolize_keys, callbacks)
|
||||
attribute_assigner = AttributeAssigner.new(build_class, evaluator, attributes)
|
||||
evaluator = evaluator_class.new(proxy, overrides.symbolize_keys)
|
||||
attribute_assigner = AttributeAssigner.new(build_class, evaluator)
|
||||
|
||||
proxy.result(attribute_assigner, to_create).tap(&block)
|
||||
end
|
||||
|
@ -104,6 +104,10 @@ module FactoryGirl
|
|||
@class_name || parent.class_name || name
|
||||
end
|
||||
|
||||
def evaluator_class
|
||||
@evaluator_class ||= EvaluatorClassDefiner.new(attributes, callbacks, parent.evaluator_class).evaluator_class
|
||||
end
|
||||
|
||||
def attributes
|
||||
compile
|
||||
AttributeList.new(@name).tap do |list|
|
||||
|
@ -120,7 +124,7 @@ module FactoryGirl
|
|||
private
|
||||
|
||||
def processing_order
|
||||
[parent, traits.reverse, @definition].flatten
|
||||
[traits.reverse, @definition].flatten
|
||||
end
|
||||
|
||||
def assert_valid_options(options)
|
||||
|
@ -145,9 +149,5 @@ module FactoryGirl
|
|||
super
|
||||
@definition = @definition.clone
|
||||
end
|
||||
|
||||
def evaluator_class_definer
|
||||
@evaluator_class_definer ||= EvaluatorClassDefiner.new(attributes)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -11,5 +11,6 @@ module FactoryGirl
|
|||
def compile; end
|
||||
def class_name; end
|
||||
def default_strategy; :create; end
|
||||
def evaluator_class; FactoryGirl::Evaluator; end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -4,9 +4,10 @@ describe FactoryGirl::EvaluatorClassDefiner do
|
|||
let(:simple_attribute) { stub("simple attribute", :name => :simple, :to_proc => lambda { 1 }) }
|
||||
let(:relative_attribute) { stub("relative attribute", :name => :relative, :to_proc => lambda { simple + 1 }) }
|
||||
let(:attribute_that_raises_a_second_time) { stub("attribute that would raise without a cache", :name => :raises_without_proper_cache, :to_proc => lambda { raise "failed" if @run; @run = true; nil }) }
|
||||
let(:callbacks) { [stub("callback 1"), stub("callback 2")] }
|
||||
|
||||
let(:attributes) { [simple_attribute, relative_attribute, attribute_that_raises_a_second_time] }
|
||||
let(:class_definer) { FactoryGirl::EvaluatorClassDefiner.new(attributes) }
|
||||
let(:class_definer) { FactoryGirl::EvaluatorClassDefiner.new(attributes, callbacks, FactoryGirl::Evaluator) }
|
||||
let(:evaluator) { class_definer.evaluator_class.new(stub("build strategy", :add_observer => true)) }
|
||||
|
||||
it "returns an evaluator when accessing the evaluator class" do
|
||||
|
@ -26,4 +27,28 @@ describe FactoryGirl::EvaluatorClassDefiner do
|
|||
2.times { evaluator.raises_without_proper_cache }
|
||||
}.to_not raise_error
|
||||
end
|
||||
|
||||
it "sets attributes on the evaluator class" do
|
||||
class_definer.evaluator_class.attribute_lists.should == [attributes]
|
||||
end
|
||||
|
||||
it "sets callbacks on the evaluator class" do
|
||||
class_definer.evaluator_class.callbacks.should == callbacks
|
||||
end
|
||||
|
||||
context "with a custom evaluator as a parent class" do
|
||||
let(:child_callbacks) { [stub("child callback 1"), stub("child callback 2")] }
|
||||
let(:child_attributes) { [stub("child attribute", :name => :simple, :to_proc => lambda { 1 })] }
|
||||
let(:child_definer) { FactoryGirl::EvaluatorClassDefiner.new(child_attributes, child_callbacks, class_definer.evaluator_class) }
|
||||
|
||||
subject { child_definer.evaluator_class }
|
||||
|
||||
it "bases its attribute lists on itself and its parent evaluator" do
|
||||
subject.attribute_lists.should == [attributes, child_attributes]
|
||||
end
|
||||
|
||||
it "bases its callbacks on itself and its parent evaluator" do
|
||||
subject.callbacks.should == callbacks + child_callbacks
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -9,4 +9,5 @@ describe FactoryGirl::NullFactory do
|
|||
its(:class_name) { should be_nil }
|
||||
its(:default_strategy) { should == :create }
|
||||
its(:attributes) { should be_an_instance_of(FactoryGirl::AttributeList) }
|
||||
its(:evaluator_class) { should == FactoryGirl::Evaluator }
|
||||
end
|
||||
|
|
Loading…
Add table
Reference in a new issue