Documentation
¶
Overview ¶
Package factorybot is a pure-Go (CGO-free) reimplementation of the deterministic core of Ruby's factory_bot gem — the fixtures-replacement library used to define factories and construct objects for tests and seeding. It reproduces the factory registry, attribute resolution, sequences, traits, associations, transient attributes, parent/child inheritance, nested factories, and the build/create callback pipeline — without any Ruby runtime.
It is the factory_bot engine for [go-embedded-ruby](https://github.com/go-embedded-ruby/ruby), but a standalone, reusable module.
What it is — and isn't ¶
Everything factory_bot does to resolve a factory into a bag of attributes is deterministic and needs no interpreter, so it lives here as pure Go: merging parent attributes, overlaying traits, evaluating static and dynamic (lazy) attribute values, advancing sequences, resolving associations, separating transient attributes, and driving the callback pipeline in factory_bot's order (after(:build) → before(:create) → persist → after(:create)).
The two things factory_bot delegates to the object model — instantiating the class and persisting it — are host seams here:
- BuildFunc instantiates a class from a resolved, non-transient attribute map and returns the object (factory_bot's initialize_with / attribute assignment). The default seam returns the attribute map itself, so the library is fully exercised without any ORM.
- PersistFunc saves a built object (factory_bot's to_create, default save!). The default seam is a no-op.
A dynamic attribute value is a Go block seam, Block (func(*Evaluator) any), mirroring factory_bot's `attr { ... }`. A future rbgo binding wires BuildFunc/PersistFunc/Block to Ruby object construction, ActiveRecord persistence, and Ruby blocks respectively.
Index ¶
- Variables
- func Reset()
- type Block
- type BuildFunc
- type Callback
- type Definition
- func (d *Definition) AfterBuild(cb Callback) *Definition
- func (d *Definition) AfterCreate(cb Callback) *Definition
- func (d *Definition) Association(name, factoryName string, overrides map[string]any, traits ...string) *Definition
- func (d *Definition) Attr(name string, value any) *Definition
- func (d *Definition) BeforeCreate(cb Callback) *Definition
- func (d *Definition) Class(class string) *Definition
- func (d *Definition) Dynamic(name string, block Block) *Definition
- func (d *Definition) Factory(name string, fn func(f *Definition)) *Definition
- func (d *Definition) Parent(parent string) *Definition
- func (d *Definition) Sequence(name string, gen func(n int) any) *Definition
- func (d *Definition) SequenceFrom(name string, start int64, gen func(n int) any) *Definition
- func (d *Definition) Trait(name string, fn func(t *Definition)) *Definition
- func (d *Definition) Transient(fn func(t *Definition)) *Definition
- type Evaluator
- type Opt
- type PersistFunc
- type Registry
- func (r *Registry) AttributesFor(name string, opts ...Opt) (map[string]any, error)
- func (r *Registry) Build(name string, opts ...Opt) (any, error)
- func (r *Registry) BuildList(name string, n int, opts ...Opt) ([]any, error)
- func (r *Registry) Create(name string, opts ...Opt) (any, error)
- func (r *Registry) CreateList(name string, n int, opts ...Opt) ([]any, error)
- func (r *Registry) Define(name string, fn func(d *Definition)) error
- func (r *Registry) Generate(name string) (any, error)
- func (r *Registry) Sequence(name string, gen func(n int) any)
- func (r *Registry) SequenceFrom(name string, start int64, gen func(n int) any)
- func (r *Registry) SetBuild(fn BuildFunc)
- func (r *Registry) SetPersist(fn PersistFunc)
- type Sequence
Constants ¶
This section is empty.
Variables ¶
var ( // ErrUnknownFactory is returned when a factory name is not registered. ErrUnknownFactory = errors.New("factorybot: unknown factory") // ErrUnknownTrait is returned when a requested trait is not defined on // the factory (or any of its ancestors). ErrUnknownTrait = errors.New("factorybot: unknown trait") // ErrUnknownSequence is returned by [Registry.Generate] for a global // sequence that was never registered. ErrUnknownSequence = errors.New("factorybot: unknown sequence") // ErrSequenceOverflow is returned when a sequence counter can no longer // be advanced without overflowing int64. ErrSequenceOverflow = errors.New("factorybot: sequence overflow") // ErrDuplicateFactory is returned by [Registry.Define] when a factory // with the same name is already registered. ErrDuplicateFactory = errors.New("factorybot: duplicate factory") // ErrParentCycle is returned when resolving a factory whose parent chain // forms a cycle. ErrParentCycle = errors.New("factorybot: parent cycle") // ErrAssociationCycle is returned when building a factory whose // association graph forms a cycle. ErrAssociationCycle = errors.New("factorybot: association cycle") )
Sentinel errors returned by the registry. Match them with errors.Is.
They mirror the exceptions factory_bot raises: a missing factory or trait (FactoryBot::Errors), a sequence that can no longer advance, a duplicate definition (DuplicateDefinitionError), a parent chain that loops, and an association graph that loops (which factory_bot would otherwise blow the stack on).
Functions ¶
Types ¶
type Block ¶
Block is the seam for a dynamic (lazy) attribute value, mirroring factory_bot's `name { ... }`. It is evaluated at build time and may read sibling attributes through the Evaluator it is handed (which memoizes each value, exactly like factory_bot's evaluator).
type BuildFunc ¶
BuildFunc is the object-instantiation seam, mirroring factory_bot's initialize_with plus attribute assignment. It receives the resolved class name and the non-transient attribute map and returns the constructed object. The default seam returns a copy of the attribute map, so the engine runs without any object model.
type Callback ¶
Callback is a build/create lifecycle hook, mirroring factory_bot's after(:build) / before(:create) / after(:create). It receives the object produced by the BuildFunc seam and the Evaluator, so it can read transient attributes. Returning a non-nil error aborts the build.
type Definition ¶
type Definition struct {
// contains filtered or unexported fields
}
Definition is the builder handed to a define/factory/trait/transient block. It records a factory's class, parent, attributes, sequences, associations, traits, nested factories, and callbacks. The same type backs traits and transient blocks (which only use a subset of its methods).
func (*Definition) AfterBuild ¶
func (d *Definition) AfterBuild(cb Callback) *Definition
AfterBuild registers an after(:build) callback.
func (*Definition) AfterCreate ¶
func (d *Definition) AfterCreate(cb Callback) *Definition
AfterCreate registers an after(:create) callback.
func (*Definition) Association ¶
func (d *Definition) Association(name, factoryName string, overrides map[string]any, traits ...string) *Definition
Association declares an association to another factory, mirroring `association :author, factory: :user, name: "x"`. An empty factoryName defaults to name. The association is built with the parent strategy (build within build, create within create). overrides and traits are applied to the associated build.
func (*Definition) Attr ¶
func (d *Definition) Attr(name string, value any) *Definition
Attr declares a static attribute, mirroring `name "value"`.
func (*Definition) BeforeCreate ¶
func (d *Definition) BeforeCreate(cb Callback) *Definition
BeforeCreate registers a before(:create) callback.
func (*Definition) Class ¶
func (d *Definition) Class(class string) *Definition
Class sets the class name passed to the BuildFunc seam, mirroring `factory :user, class: "User"`. When unset it defaults to the factory name (or is inherited from the parent).
func (*Definition) Dynamic ¶
func (d *Definition) Dynamic(name string, block Block) *Definition
Dynamic declares a lazily evaluated attribute, mirroring `name { ... }`. The block may read sibling attributes through the Evaluator.
func (*Definition) Factory ¶
func (d *Definition) Factory(name string, fn func(f *Definition)) *Definition
Factory declares a nested (child) factory that inherits from the enclosing one, mirroring a `factory :admin do ... end` nested inside another factory.
func (*Definition) Parent ¶
func (d *Definition) Parent(parent string) *Definition
Parent sets the parent factory to inherit attributes, traits, and callbacks from, mirroring `factory :admin, parent: :user`.
func (*Definition) Sequence ¶
func (d *Definition) Sequence(name string, gen func(n int) any) *Definition
Sequence declares a per-factory sequence starting at 1, mirroring `sequence(:email) { |n| ... }`. Pass a nil generator to yield the raw number.
func (*Definition) SequenceFrom ¶
func (d *Definition) SequenceFrom(name string, start int64, gen func(n int) any) *Definition
SequenceFrom is Definition.Sequence with an explicit starting value, mirroring `sequence(:email, 1000) { |n| ... }`.
func (*Definition) Trait ¶
func (d *Definition) Trait(name string, fn func(t *Definition)) *Definition
Trait declares a named attribute overlay, mirroring `trait :admin do ... end`. A trait may itself declare attributes and callbacks; applying it overlays them at build time.
func (*Definition) Transient ¶
func (d *Definition) Transient(fn func(t *Definition)) *Definition
Transient declares transient attributes, mirroring `transient do ... end`. They are available to other attributes and callbacks through the evaluator but are never passed to the BuildFunc seam.
type Evaluator ¶
type Evaluator struct {
// contains filtered or unexported fields
}
Evaluator resolves and memoizes a factory's attribute values during a build, mirroring factory_bot's evaluator. Dynamic attribute blocks and callbacks receive it and read sibling/transient attributes through Evaluator.Get.
func (*Evaluator) Get ¶
Get returns the (memoized) value of the named attribute for use inside a dynamic block or callback, mirroring reading a sibling in factory_bot's evaluator. An unknown name yields nil. If resolving the attribute fails (for example a sequence overflow or an association cycle), Get panics with an internal marker that the build recovers and returns as an error.
type Opt ¶
type Opt func(*callOptions)
Opt configures a Build/Create/AttributesFor call.
type PersistFunc ¶
PersistFunc is the persistence seam, mirroring factory_bot's to_create (default save!). It is invoked by Create/CreateList after the object is built and before(:create) callbacks have run. The default seam is a no-op.
type Registry ¶
type Registry struct {
// contains filtered or unexported fields
}
Registry holds factory definitions and global sequences and constructs objects, mirroring FactoryBot's module-level registry.
func Default ¶
func Default() *Registry
Default returns the process-wide default registry, the one a future rbgo binding maps the FactoryBot module onto.
func New ¶
func New() *Registry
New returns an empty registry with default (map-returning / no-op) seams.
func (*Registry) AttributesFor ¶
AttributesFor returns the resolved non-transient, non-association attributes without instantiating anything, mirroring `FactoryBot.attributes_for(:user, ...)`.
func (*Registry) Build ¶
Build constructs an object without persisting it, mirroring `FactoryBot.build(:user, ...)`.
func (*Registry) BuildList ¶
BuildList builds n objects, mirroring `FactoryBot.build_list(:user, n, ...)`.
func (*Registry) Create ¶
Create constructs and persists an object, mirroring `FactoryBot.create(:user, ...)`.
func (*Registry) CreateList ¶
CreateList creates n objects, mirroring `FactoryBot.create_list(:user, n, ...)`.
func (*Registry) Define ¶
func (r *Registry) Define(name string, fn func(d *Definition)) error
Define registers a factory, mirroring `factory :name do ... end` inside `FactoryBot.define`. The block configures the factory through its Definition; nested factories are registered as children. It returns ErrDuplicateFactory if the name (or any nested name) is already registered.
func (*Registry) Generate ¶
Generate advances a global sequence and returns its value, mirroring `FactoryBot.generate(:email)`. It returns ErrUnknownSequence if no such sequence is registered.
func (*Registry) Sequence ¶
Sequence registers a global sequence starting at 1, mirroring a top-level `sequence(:email) { |n| ... }`. Advance it with Registry.Generate.
func (*Registry) SequenceFrom ¶
SequenceFrom is Registry.Sequence with an explicit starting value.
func (*Registry) SetPersist ¶
func (r *Registry) SetPersist(fn PersistFunc)
SetPersist installs the persistence seam (see PersistFunc).
type Sequence ¶
type Sequence struct {
// contains filtered or unexported fields
}
Sequence is a monotonically increasing counter with an optional generator, mirroring factory_bot's sequence(:name) { |n| ... }. The counter starts at 1 by default (factory_bot's default) and is shared across every build that touches it, so successive objects receive successive values.
