Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rough draft of Namespaced Factories #1453

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
44 changes: 40 additions & 4 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ jobs:
ruby:
- jruby-9.2.16.0
- truffleruby
- "3.1"
- "3.0"
- "2.7"
- "2.6"
Expand All @@ -23,25 +24,47 @@ jobs:
- "5.2"
- "6.0"
- "6.1"
- "7.0"
- main
exclude:
- ruby: 2.5
rails: "7.0"
- ruby: 2.5
rails: main
- ruby: 2.6
rails: "7.0"
- ruby: 2.6
rails: main
- ruby: jruby-9.2.16.0
rails: "7.0"
- ruby: jruby-9.2.16.0
rails: main
- ruby: 3.0
- ruby: "3.0"
rails: "5.0"
- ruby: "3.0"
rails: "5.1"
- ruby: "3.0"
rails: "5.2"
- ruby: truffleruby
rails: "5.0"
- ruby: truffleruby
rails: "5.1"
- ruby: truffleruby
rails: "5.2"
- ruby: "3.1"
rails: "5.0"
- ruby: 3.0
- ruby: "3.1"
rails: "5.1"
- ruby: 3.0
- ruby: "3.1"
rails: "5.2"
- ruby: "3.1"
rails: "6.0"

runs-on: 'ubuntu-latest'

env:
BUNDLE_GEMFILE: gemfiles/${{ matrix.rails }}.gemfile
RUBYOPT: "--disable-error_highlight"

steps:
- uses: actions/checkout@v2
Expand All @@ -51,4 +74,17 @@ jobs:
- name: Setup project
run: bundle install
- name: Run test
run: bundle exec rake
run: bundle exec rake all_specs

standard:
name: Run standard
runs-on: 'ubuntu-latest'
steps:
- uses: actions/checkout@v2
- uses: ruby/setup-ruby@v1
with:
ruby-version: "3.1"
- name: Setup project
run: bundle install
- name: Run test
run: bundle exec rake standard
1 change: 1 addition & 0 deletions .standard.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ruby_version: "2.5"
6 changes: 6 additions & 0 deletions Appraisals
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@ appraise "6.1" do
gem "sqlite3", platforms: [:ruby]
end

appraise "7.0" do
gem "activerecord", "~> 7.0.0"
gem "activerecord-jdbcsqlite3-adapter", "~> 61.0", platforms: [:jruby]
gem "sqlite3", platforms: [:ruby]
end

appraise "main" do
gem "activerecord", git: "https://github.com/rails/rails.git", branch: "main"
gem "activerecord-jdbcsqlite3-adapter", "~> 61.0", platforms: [:jruby]
Expand Down
31 changes: 31 additions & 0 deletions GETTING_STARTED.md
Original file line number Diff line number Diff line change
Expand Up @@ -1196,6 +1196,28 @@ factory :user do
end
```

### As mixins

Traits can be defined outside of factories and used as mixins to compose shared attributes

```ruby
FactoryBot.define do
trait :timestamps do
created_at { 8.days.ago }
updated_at { 4.days.ago }
end

factory :user, traits: [:timestamps] do
username { "john_doe" }
end

factory :post do
timestamps
title { "Traits rock" }
end
end
```

### Using traits

Traits can also be passed in as a list of symbols when you construct an instance
Expand Down Expand Up @@ -1583,6 +1605,15 @@ twenty_somethings = build_list(:user, 10) do |user, i|
end
```

`create_list` passes saved instances into the block. If you modify the instance, you must save it again:

```ruby
twenty_somethings = create_list(:user, 10) do |user, i|
user.date_of_birth = (20 + i).years.ago
user.save!
end
```

`build_stubbed_list` will give you fully stubbed out instances:

```ruby
Expand Down
32 changes: 16 additions & 16 deletions Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
PATH
remote: .
specs:
factory_bot (6.2.0)
factory_bot (6.2.1)
activesupport (>= 5.0.0)

GEM
Expand Down Expand Up @@ -72,17 +72,17 @@ GEM
middleware (0.1.0)
minitest (5.14.3)
multi_test (0.1.2)
parallel (1.20.1)
parser (3.0.0.0)
parallel (1.21.0)
parser (3.1.0.0)
ast (~> 2.4.1)
protobuf-cucumber (3.10.8)
activesupport (>= 3.2)
middleware
thor
thread_safe
rainbow (3.0.0)
rainbow (3.1.1)
rake (13.0.3)
regexp_parser (2.0.3)
regexp_parser (2.2.0)
rexml (3.2.5)
rspec (3.10.0)
rspec-core (~> 3.10.0)
Expand All @@ -100,19 +100,19 @@ GEM
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.10.0)
rspec-support (3.10.2)
rubocop (1.10.0)
rubocop (1.24.1)
parallel (~> 1.10)
parser (>= 3.0.0.0)
rainbow (>= 2.2.2, < 4.0)
regexp_parser (>= 1.8, < 3.0)
rexml
rubocop-ast (>= 1.2.0, < 2.0)
rubocop-ast (>= 1.15.1, < 2.0)
ruby-progressbar (~> 1.7)
unicode-display_width (>= 1.4.0, < 3.0)
rubocop-ast (1.4.1)
parser (>= 2.7.1.5)
rubocop-performance (1.9.2)
rubocop (>= 0.90.0, < 2.0)
rubocop-ast (1.15.1)
parser (>= 3.0.1.1)
rubocop-performance (1.13.1)
rubocop (>= 1.7.0, < 2.0)
rubocop-ast (>= 0.4.0)
ruby-progressbar (1.11.0)
simplecov (0.21.2)
Expand All @@ -122,16 +122,16 @@ GEM
simplecov-html (0.12.3)
simplecov_json_formatter (0.1.2)
sqlite3 (1.4.2)
standard (0.13.0)
rubocop (= 1.10.0)
rubocop-performance (= 1.9.2)
standard (1.6.0)
rubocop (= 1.24.1)
rubocop-performance (= 1.13.1)
sys-uname (1.2.2)
ffi (~> 1.1)
thor (1.1.0)
thread_safe (0.3.6)
tzinfo (2.0.4)
concurrent-ruby (~> 1.0)
unicode-display_width (2.0.0)
unicode-display_width (2.1.0)
yard (0.9.26)
zeitwerk (2.4.2)

Expand All @@ -154,4 +154,4 @@ DEPENDENCIES
yard

BUNDLED WITH
2.2.16
2.3.5
7 changes: 7 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# News

## 6.2.1 (March 8, 2022)
* Added: CI testing against truffleruby
* Changed: Documentation improvements for sequences and traits
* Fixed: ActiveSupport::Notifications reporting strategy through associations now report as symbols
* BREAKING CHANGE: Custom strategies now need to define a `to_sym` method to specify the strategy identifier
* Fixed: `add_attribute` with reserved keywords assigns values correctly

## 6.2.0 (May 7, 2021)
* Added: support for Ruby 3.0
* Changed: Include factory or trait name in error messages for missing traits. d05a9a3c
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ community](https://github.com/thoughtbot/factory_bot/graphs/contributors).
License
-------

factory_bot is Copyright © 2008-2020 Joe Ferris and thoughtbot. It is free
factory_bot is Copyright © 2008-2022 Joe Ferris and thoughtbot. It is free
software, and may be redistributed under the terms specified in the
[LICENSE] file.

Expand All @@ -94,8 +94,8 @@ See [our other projects][community] or

[community]: https://thoughtbot.com/community?utm_source=github
[hire]: https://thoughtbot.com/hire-us?utm_source=github
[ci-image]: https://github.com/thoughtbot/factory_bot/actions/workflows/build.yml/badge.svg
[ci]: https://github.com/thoughtbot/factory_bot/actions?query=workflow%3A.github%2Fworkflows%2Fbuild.yml+branch%3Amaster++
[ci-image]: https://github.com/thoughtbot/factory_bot/actions/workflows/build.yml/badge.svg?branch=main
[ci]: https://github.com/thoughtbot/factory_bot/actions?query=workflow%3ABuild+branch%3Amain
[grade-image]: https://codeclimate.com/github/thoughtbot/factory_bot/badges/gpa.svg
[grade]: https://codeclimate.com/github/thoughtbot/factory_bot
[version-image]: https://badge.fury.io/rb/factory_bot.svg
Expand Down
7 changes: 5 additions & 2 deletions Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,11 @@ require "standard/rake"

Bundler::GemHelper.install_tasks(name: "factory_bot")

desc "Default: run the specs, features, and standard ."
task default: %w[spec:unit spec:acceptance features standard]
desc "Default: run all specs and standard"
task default: %w[all_specs standard]

desc "Run all specs and features"
task all_specs: %w[spec:unit spec:acceptance features]

namespace :spec do
desc "Run unit specs"
Expand Down
9 changes: 9 additions & 0 deletions gemfiles/7.0.gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# This file was generated by Appraisal

source "https://rubygems.org"

gem "activerecord-jdbcsqlite3-adapter", "~> 61.0", platforms: [:jruby]
gem "sqlite3", platforms: [:ruby]
gem "activerecord", "~> 7.0.0"

gemspec name: "factory_bot", path: "../"
1 change: 1 addition & 0 deletions lib/factory_bot.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
require "factory_bot/null_object"
require "factory_bot/evaluation"
require "factory_bot/factory"
require "factory_bot/namespaced_factory"
require "factory_bot/attribute_assigner"
require "factory_bot/evaluator"
require "factory_bot/evaluator_class_definer"
Expand Down
2 changes: 1 addition & 1 deletion lib/factory_bot/decorator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ def send(...)
end
RUBY
else
def method_missing(name, *args, &block) # rubocop:disable Style/MethodMissingSuper, Style/MissingRespondToMissing
def method_missing(name, *args, &block) # rubocop:disable Style/MissingRespondToMissing
@component.send(name, *args, &block)
end

Expand Down
2 changes: 1 addition & 1 deletion lib/factory_bot/definition_proxy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ def transient(&block)
# end
#
# are equivalent.
def method_missing(name, *args, &block) # rubocop:disable Style/MissingRespondToMissing, Style/MethodMissingSuper
def method_missing(name, *args, &block) # rubocop:disable Style/MissingRespondToMissing
association_options = args.first

if association_options.nil?
Expand Down
4 changes: 2 additions & 2 deletions lib/factory_bot/evaluator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ def initialize(build_strategy, overrides = {})
def association(factory_name, *traits_and_overrides)
overrides = traits_and_overrides.extract_options!
strategy_override = overrides.fetch(:strategy) {
FactoryBot.use_parent_strategy ? @build_strategy.class : :create
FactoryBot.use_parent_strategy ? @build_strategy.to_sym : :create
}

traits_and_overrides += [overrides.except(:strategy)]
Expand All @@ -35,7 +35,7 @@ def association(factory_name, *traits_and_overrides)

attr_accessor :instance

def method_missing(method_name, *args, &block) # rubocop:disable Style/MethodMissingSuper, Style/MissingRespondToMissing
def method_missing(method_name, *args, &block)
if @instance.respond_to?(method_name)
@instance.send(method_name, *args, &block)
else
Expand Down
37 changes: 37 additions & 0 deletions lib/factory_bot/namespaced_factory.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
module FactoryBot
# See:
# - https://github.com/thoughtbot/factory_bot/issues/199
# - https://github.com/thoughtbot/factory_bot/commit/652818bd1701db67ea03cd062c8259cd7fb37807
#
# There are two main use-cases for Namespaced Factories:
# 1. Sharing Factories from an Engine or Gem
# 2. Decomposing an application using domain driven design
class NamespacedFactory
def initialize(namespace, options)
@namespace = namespace
@options = options
@prefix = options.fetch(:prefix, "#{namespace.to_s.underscore}_")
@require_prefix = options.fetch(:require_prefix, true)
end

def factory(name, options = {}, &block)
__dsl__.factory("#{prefix}#{name}".to_sym, options.merge(class: "#{namespace}::#{name.to_s.classify}"), &block)
return unless register_without_namespace?(name)
__dsl__.factory(name.to_sym, options.merge(class: "#{namespace}::#{name.to_s.classify}"), &block)
end

private

attr_reader :namespace, :require_prefix, :prefix

alias require_prefix? require_prefix

def register_without_namespace?(name)
!require_prefix? && !Internal.factories.registered?(name)
end

def __dsl__
@dsl ||= FactoryBot::Syntax::Default::DSL.new
end
end
end
4 changes: 4 additions & 0 deletions lib/factory_bot/strategy/attributes_for.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ def association(runner)
def result(evaluation)
evaluation.hash
end

def to_sym
:attributes_for
end
end
end
end
4 changes: 4 additions & 0 deletions lib/factory_bot/strategy/build.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ def result(evaluation)
evaluation.notify(:after_build, instance)
end
end

def to_sym
:build
end
end
end
end
4 changes: 4 additions & 0 deletions lib/factory_bot/strategy/create.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ def result(evaluation)
evaluation.notify(:after_create, instance)
end
end

def to_sym
:create
end
end
end
end