Skip to content

Instantly share code, notes, and snippets.

@caius
Last active November 30, 2021 23:27
Show Gist options
  • Save caius/768dcc66a2a6ce4a1f95dbc1bada05de to your computer and use it in GitHub Desktop.
Save caius/768dcc66a2a6ce4a1f95dbc1bada05de to your computer and use it in GitHub Desktop.
require "factory_bot"
require "active_support/all"
module LocalFactory
class Factory
attr_reader :factories
def initialize
@factories = {}
end
# Public: factory method to build a FactoryBot factory out
#
# @param name [Symbol, #to_sym] name of the factory, passed to `build` later
# @param class: [Object] class the factory should instantiate
# @param **options [Hash] @see FactoryBot::Factory#initialize
# @param &block [Proc] @see FactoryBot::DefinitionProxy for available methods
# @return nothing
#
# @example defining and using factory in spec
#
# RSpec.describe "testing some crazy idea out" do
# include LocalFactory
#
# local_factory.factory(:user) do
# sequence(:name) { |n| "User #{n}" }
# age { 0xBADC0FFEE }
# end
#
# it "things" do
# thing = local_factory.build(:user, age: 911)
# expect(thing.name).to eq("User 1")
# expect(thing.age).to eq(911)
# end
# end
#
def factory(name, **options, &block)
klass = options.key?(:class) ? options.delete(:class) : OpenStruct
factories[name.to_sym] = FactoryBot::Factory.new(name, class: klass, **options)
# Apply definition to factory through definition proxy (hattip to FactoryBot source code)
FactoryBot::DefinitionProxy.new(factories[name.to_sym].definition).instance_eval(&block)
nil
end
# Public: build an instance from a factory
#
# @param name [Symbol, #to_sym] name of the factory to invoke
# @param **overrides [Hash] @see FactoryBot::Factory#run for options
# @return [Object] instantiated instance from factory
def build(name, **overrides)
factories.fetch(name.to_sym).run(FactoryBot::Strategy::Build, overrides)
end
end
# Internal: setup spec class for localised factorying
#
# You could argue this is the local factory factory. /me laughs in java
#
# @param klass [Object] class object module included into
# @return nothing
def self.included(klass)
klass.cattr_accessor :local_factory
klass.local_factory = Factory.new
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment