Class: Philiprehberger::TestFactory::Builder

Inherits:
Object
  • Object
show all
Defined in:
lib/philiprehberger/test_factory/builder.rb

Overview

Builds data hashes from factory definitions.

Instance Method Summary collapse

Constructor Details

#initialize(registry) ⇒ Builder

Create a new builder.

Parameters:

  • registry (Registry)

    the registry to look up definitions



10
11
12
# File 'lib/philiprehberger/test_factory/builder.rb', line 10

def initialize(registry)
  @registry = registry
end

Instance Method Details

#build(name, traits: [], **overrides) ⇒ Hash

Build a single data hash from a factory definition.

Parameters:

  • name (Symbol)

    factory name

  • traits (Array<Symbol>) (defaults to: [])

    trait names to apply

  • overrides (Hash)

    explicit attribute overrides

Returns:

  • (Hash)

    the built data hash

Raises:

  • (Error)

    if the factory is not defined



21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/philiprehberger/test_factory/builder.rb', line 21

def build(name, traits: [], **overrides)
  entry = @registry.get(name)
  raise Error, "Factory :#{name} is not defined" unless entry

  block = entry[:block]
  proxy = entry[:proxy]

  # Evaluate the definition block to get fresh default attributes.
  # For blocks accepting a proxy parameter, use a NullProxy to discard
  # DSL re-registrations (they were already captured at define time).
  result = if block.arity.zero?
             block.call
           else
             null_proxy = NullProxy.new
             null_proxy.instance_exec(null_proxy, &block)
           end

  # Apply traits
  traits.each { |t| result = apply_trait(name, t, result) }

  # Separate transient overrides from regular overrides
  transient_keys = proxy.transient_attributes.keys
  transient_values = proxy.transient_attributes.dup
  regular_overrides = {}

  overrides.each do |key, value|
    if transient_keys.include?(key)
      transient_values[key] = value
    else
      regular_overrides[key] = value
    end
  end

  # Build associations
  proxy.associations.each do |attr_name, factory_name|
    result[attr_name] = if regular_overrides.key?(attr_name)
                          # If overridden, use the override directly (no factory build)
                          regular_overrides.delete(attr_name)
                        else
                          build(factory_name)
                        end
  end

  # Apply regular overrides
  result.merge!(regular_overrides)

  # Remove transient attributes from the result
  transient_keys.each { |key| result.delete(key) }

  # Run after_build callbacks with the result and transient context
  proxy.after_build_callbacks.each { |cb| cb.call(result, transient_values) }

  result
end

#build_list(name, count, traits: [], **overrides) ⇒ Array<Hash>

Build a list of data hashes.

Each element goes through the normal build path so sequences, associations, and callbacks run once per object. Overrides and traits apply identically to every element in the list.

Parameters:

  • name (Symbol)

    factory name

  • count (Integer)

    number of items to build (must be >= 0)

  • traits (Array<Symbol>) (defaults to: [])

    trait names to apply

  • overrides (Hash)

    explicit attribute overrides

Returns:

  • (Array<Hash>)

    the built data hashes

Raises:

  • (ArgumentError)

    if count is negative



88
89
90
91
92
# File 'lib/philiprehberger/test_factory/builder.rb', line 88

def build_list(name, count, traits: [], **overrides)
  raise ArgumentError, "count must be non-negative, got #{count}" if count.negative?

  Array.new(count) { build(name, traits: traits, **overrides) }
end