thoughtbot / thoughtbot/factory_bot

Question: Why `Evaluator` class is marked as a `@api private` if its instance is part of `to_create` API?

Open
#1,664 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Ruby
Stars
8.2k
Forks
2.6k
PR merge metrics
No merged PRs in 30d

Description

to_create has either arity of one - to_create {|instance| do something } or two to_create {|instance, context| do something with instance and context }

For the context, we are using repository pattern in our app, the entities are immutable structs, so building them is simply initializing a class. Same time persistence is a create(**attrs) method in a repo instance, that returns an entity after saving it to a DB.

This is the snippet I've came up with after some experimenting:

module FactoryBotHelpers
  # no clean way (only chain of private methods and vars) to pass our repo class to both initialize_with and to_create
  # custom strategies also don't provide access to the class of the factory for some reason
  # hence, this helper method
  def factory(name, repo_class:, &)
    # values that are mandatory to initialize our immutable entities,
    # but are set in most cases by ORM when persisting
    missing_build_attributes = {
      id: -> { GenerateULID.call },
    }

    FactoryBot.define do
      # expectation was that class won't be required as we are overriding initialize_with
      # but FactoryBot still tries to figure out class name from factory name
      factory name, class: repo_class do
        initialize_with do
          repo_class.constantize.new.entity_class.new(
            **missing_build_attributes.transform_values(&:call),
            **attributes,
          )
        end

        to_create do |instance, context|
          repo_class.constantize.new.create!(
            **instance.attributes.except(
              # we need to remove default values that we supplied in initialize_with, but
              # we also need to keep the values that were set by the test
              missing_build_attributes.keys - context.__override_names__,
            ),
          )
        end

        instance_eval(&)
      end
    end
  end
  module_function :factory
end

But in this case requires access to the names of the overridden attributes via __override_names__. Is it discouraged?

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the Evaluator class and the to_create callback API referenced in the issue, then check how override_names is exposed. A useful resolution should state whether accessing this private API is supported and, if so, document the supported entry point or explain the intended alternative.

Written by the indexing model from the issue text.

Assessment

Tech stack
ruby
Domain
testing
Issue type
Documentation
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.