This includes #callbacks, #constructor, and #to_create. The reasoning
behind this is that we were mimicing an inheritance chain via methods;
now, we actually generate classes, which Factory maintains, who inherit
from their parent's hierarchy. We build the hierarchy during compilation
to conditionally define methods based on whether what we're dealing
with from the definition is actually meaningful. The base class
(DefinitionHierarchy) uses the defaults (an empty array for #callbacks
and the global #to_create and #constructor) so once we hit the top
level, if the definition doesn't set any overrides, we have a list of
sensible values.
The previous implementation of trait handling within the Definition
didn't account for when implicit traits were used within other traits.
This is useful if you have two different traits, but one depends on
another; for example, a refunded order and a completed order could both
have the attribute `completed_at` set, but refunded would additionally
have `refunded_at` set:
FactoryGirl.define do
factory :order do
trait :completed do
completed_at { 3.days.ago }
end
trait :refunded do
completed
refunded_at { 1.day.ago }
end
end
end
This also tests to make sure that callbacks, custom constructors, and
creation overrides work correctly when implicit traits are used within
other traits.
Fixes#360
evaluator_class contains the fully-inherited list of attributes; this
includes parent classes, traits, etc. When calculating associations for
an individual factory, the factory should use inheritance to build the
list instead of merely accessing association attributes on itself.
Closes#293
Factory Girl now allows factories to override object instantiation. This
means factories can use factory methods (e.g. methods other than new) as
well as pass arguments explicitly.
factory :user do
ignore do
things { ["thing 1", "thing 2"] }
end
initialize_with { User.construct_with_things(things) }
end
factory :report_generator do
ignore do
name { "Generic Report" }
data { {:foo => "bar", :baz => "buzz"} }
end
initialize_with { ReportGenerator.new(name, data) }
end
Whitespace
Code recommendations
DeclarationList knows how to generate an attribute
list, which never really made sense outside of being generated from
declarations. Now, the declaration list builds a list of attributes
which is combined in Factory#attributes with attributes from traits and
its parents.