Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Factory evaluators use inheritance

  • Loading branch information...
commit f2e41389ea3f8fd455d7a14a0241c6a1ce8d801a 1 parent ac1df1d
@joshuaclayton joshuaclayton authored
View
4 lib/factory_girl/attribute_assigner.rb
@@ -2,10 +2,10 @@
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
View
15 lib/factory_girl/evaluator.rb
@@ -1,13 +1,24 @@
+require "active_support/core_ext/class/attribute"
@ngan
ngan added a note

Rails 2.3 does not have this...

I'm getting the following error:

activesupport-2.3.2/lib/active_support/dependencies.rb:158:in `require': no such file to load -- active_support/core_ext/class/attribute (MissingSourceFile)
@joshuaclayton Owner

Ah, it was introduced in 2.3.9. I'll update the gemspec to require that as a minimum.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+
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
View
13 lib/factory_girl/evaluator_class_definer.rb
@@ -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
View
14 lib/factory_girl/factory.rb
@@ -40,8 +40,8 @@ def run(proxy_class, overrides, &block) #:nodoc:
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 @@ def class_name #:nodoc:
@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 @@ def callbacks
private
def processing_order
- [parent, traits.reverse, @definition].flatten
+ [traits.reverse, @definition].flatten
end
def assert_valid_options(options)
@@ -145,9 +149,5 @@ def initialize_copy(source)
super
@definition = @definition.clone
end
-
- def evaluator_class_definer
- @evaluator_class_definer ||= EvaluatorClassDefiner.new(attributes)
- end
end
end
View
1  lib/factory_girl/null_factory.rb
@@ -11,5 +11,6 @@ def initialize
def compile; end
def class_name; end
def default_strategy; :create; end
+ def evaluator_class; FactoryGirl::Evaluator; end
end
end
View
27 spec/factory_girl/evaluator_class_definer_spec.rb
@@ -4,9 +4,10 @@
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 @@
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
View
1  spec/factory_girl/null_factory_spec.rb
@@ -9,4 +9,5 @@
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

0 comments on commit f2e4138

Please sign in to comment.
Something went wrong with that request. Please try again.