factory_bot-with 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/main.yml +2 -1
- data/CHANGELOG.md +5 -0
- data/README.md +23 -3
- data/lib/factory_bot/with/proxy.rb +6 -9
- data/lib/factory_bot/with/version.rb +1 -1
- data/lib/factory_bot/with.rb +32 -4
- metadata +3 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 880e6e75c055c95bf4c8afab93288afaeb01f1a8ea7d162ecec04c3adaba1498
|
4
|
+
data.tar.gz: d59eb2dbc2c24256e1c1b4053d194de41378cdd3773c06375bf8617ae63af642
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 74ee4b6d1718cfef30a3ddfaaca2486f854c8c6db5c4b1fa63c1947f2ae3f2430e8ec67afd8dac052ff049df4d61c7f091b66a0080d187e51e58c4795534b66f
|
7
|
+
data.tar.gz: f01718b24e04fe024189d77cec858f0aad8ec88fac9de520ced36bf954863775e6c0ecb079d0831016fac2d863edec204c8a23bec82f304ecd2b8c4186c9ab5e
|
data/.github/workflows/main.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,10 @@
|
|
1
1
|
## [Unreleased]
|
2
2
|
|
3
|
+
## [0.4.0]
|
4
|
+
|
5
|
+
- Fixed: Improved error message for incorrect factory usage
|
6
|
+
- Added: Added `with` scope syntax for automatic association resolution
|
7
|
+
|
3
8
|
## [0.3.0] - 2024-12-09
|
4
9
|
|
5
10
|
- Added: Added `FactoryBot::With.register_strategy` to support custom strategies
|
data/README.md
CHANGED
@@ -5,6 +5,8 @@
|
|
5
5
|
|
6
6
|
FactoryBot::With is a FactoryBot extension that wraps `FactoryBot::Syntax::Methods` to make it a little easier to use.
|
7
7
|
|
8
|
+
[FactoryBot における関連の扱いと、factory_bot-with gem を作った話 (Japanese)](https://zenn.dev/yubrot/articles/032447068e308e)
|
9
|
+
|
8
10
|
For example, with these factories:
|
9
11
|
|
10
12
|
```ruby
|
@@ -143,16 +145,18 @@ create.blog(with.article) # autocomplete to :blog_article
|
|
143
145
|
|
144
146
|
</details>
|
145
147
|
|
148
|
+
## Additional features
|
149
|
+
|
146
150
|
### `with` as a template
|
147
151
|
|
148
|
-
`with` can also be used stand-alone. It works as a template for factory method calls.
|
152
|
+
`with` can also be used stand-alone. Stand-alone `with` can be used in place of the factory name. It works as a template for factory method calls.
|
149
153
|
|
150
154
|
Instead of writing:
|
151
155
|
|
152
156
|
```ruby
|
153
157
|
let(:story) { create(:story, *story_args, **story_kwargs) }
|
154
158
|
let(:story_args) { [] }
|
155
|
-
let(:story_kwargs) { {} }
|
159
|
+
let(:story_kwargs) { { category: "SF" } }
|
156
160
|
|
157
161
|
context "when published more than one year ago" do
|
158
162
|
let(:story_args) { [*super(), :published] }
|
@@ -167,7 +171,7 @@ You can write like this:
|
|
167
171
|
```ruby
|
168
172
|
# Factory methods accept a With instance as a first argument:
|
169
173
|
let(:story) { create(story_template) }
|
170
|
-
let(:story_template) { with.story }
|
174
|
+
let(:story_template) { with.story(category: "SF") }
|
171
175
|
|
172
176
|
context "when published more than one year ago" do
|
173
177
|
let(:story_template) { with(super(), :published, start_at: 2.year.ago) }
|
@@ -176,6 +180,22 @@ context "when published more than one year ago" do
|
|
176
180
|
end
|
177
181
|
```
|
178
182
|
|
183
|
+
### `with` scope for automatic association resolution
|
184
|
+
|
185
|
+
By calling `with` without positional arguments, but with keyword arguments that define the relationship between factory names and objects, along with a block, `factory_bot-with` creates a scope where those objects become candidates for automatic association resolution.
|
186
|
+
|
187
|
+
```ruby
|
188
|
+
let(:blog) { create.blog }
|
189
|
+
|
190
|
+
before do
|
191
|
+
with(blog:) do
|
192
|
+
# Just like when using create.blog, blog is automatically resolved when create.article is called
|
193
|
+
create.article(with.comment)
|
194
|
+
create.article(with_list.comment(3))
|
195
|
+
end
|
196
|
+
end
|
197
|
+
```
|
198
|
+
|
179
199
|
## Development
|
180
200
|
|
181
201
|
```bash
|
@@ -4,31 +4,28 @@ module FactoryBot
|
|
4
4
|
class With
|
5
5
|
# An intermediate object to provide some notation combined with <code>method_missing</code>.
|
6
6
|
# @example
|
7
|
-
# class
|
8
|
-
# def foo(name = nil)
|
7
|
+
# class Example
|
8
|
+
# def foo(name = nil, ...)
|
9
9
|
# return FactoryBot::With::Proxy.new(self, __method__) unless name
|
10
10
|
#
|
11
11
|
# name
|
12
12
|
# end
|
13
13
|
# end
|
14
14
|
#
|
15
|
-
#
|
15
|
+
# ex = Example.new
|
16
|
+
# ex.foo.bar #=> :bar
|
16
17
|
class Proxy < BasicObject
|
17
18
|
# @param receiver [Object]
|
18
19
|
# @param method [Symbol]
|
19
|
-
|
20
|
-
def initialize(receiver, method, *preargs)
|
20
|
+
def initialize(receiver, method)
|
21
21
|
@receiver = receiver
|
22
22
|
@method = method
|
23
|
-
@preargs = preargs
|
24
23
|
end
|
25
24
|
|
26
25
|
# @!visibility private
|
27
26
|
def respond_to_missing?(_method_name, _) = true
|
28
27
|
|
29
|
-
def method_missing(method_name, ...)
|
30
|
-
@receiver.__send__(@method, *@preargs, method_name, ...)
|
31
|
-
end
|
28
|
+
def method_missing(method_name, ...) = @receiver.__send__(@method, method_name, ...)
|
32
29
|
end
|
33
30
|
end
|
34
31
|
end
|
data/lib/factory_bot/with.rb
CHANGED
@@ -96,7 +96,7 @@ module FactoryBot
|
|
96
96
|
# @param build_strategy [Symbol]
|
97
97
|
# @param ancestors [Array<Array(AssocInfo, Object)>, nil]
|
98
98
|
# @return [Object]
|
99
|
-
def instantiate(build_strategy, ancestors =
|
99
|
+
def instantiate(build_strategy, ancestors = self.class.scoped_ancestors)
|
100
100
|
return self if build_strategy == :with
|
101
101
|
|
102
102
|
factory_bot_method =
|
@@ -148,12 +148,40 @@ module FactoryBot
|
|
148
148
|
list: :"#{build_strategy}_list",
|
149
149
|
}.each do |variation, method_name|
|
150
150
|
Methods.define_method(method_name) do |factory = nil, *args, **kwargs, &block|
|
151
|
-
|
152
|
-
|
153
|
-
|
151
|
+
if factory
|
152
|
+
# <__method__>(<factory_name>, ...)
|
153
|
+
With.build(variation, factory, *args, **kwargs, &block).instantiate(build_strategy)
|
154
|
+
elsif args.empty? && kwargs.empty? && !block
|
155
|
+
# <__method__>.<factory_name>(...)
|
156
|
+
Proxy.new(self, __method__)
|
157
|
+
elsif __method__ == :with && args.empty? && !kwargs.empty?
|
158
|
+
# with(<factory_name>: <object>, ...) { ... }
|
159
|
+
With.with_scoped_ancestors(kwargs, &block)
|
160
|
+
else
|
161
|
+
raise ArgumentError, "Invalid use of #{__method__}"
|
162
|
+
end
|
154
163
|
end
|
155
164
|
end
|
156
165
|
end
|
166
|
+
|
167
|
+
# @!visibility private
|
168
|
+
# @param objects [{Symbol => Object}]
|
169
|
+
def with_scoped_ancestors(objects)
|
170
|
+
return unless block_given?
|
171
|
+
|
172
|
+
tmp_scoped_ancestors = scoped_ancestors
|
173
|
+
Thread.current[:factory_bot_with_scoped_ancestors] = [
|
174
|
+
*objects.map { [AssocInfo.get(_1), _2] },
|
175
|
+
*tmp_scoped_ancestors || [],
|
176
|
+
]
|
177
|
+
result = yield
|
178
|
+
Thread.current[:factory_bot_with_scoped_ancestors] = tmp_scoped_ancestors
|
179
|
+
result
|
180
|
+
end
|
181
|
+
|
182
|
+
# @!visibility private
|
183
|
+
# @return [Array<Array(AssocInfo, Object)>, nil]
|
184
|
+
def scoped_ancestors = Thread.current[:factory_bot_with_scoped_ancestors]
|
157
185
|
end
|
158
186
|
|
159
187
|
%i[build build_stubbed create attributes_for with].each { register_strategy _1 }
|
metadata
CHANGED
@@ -1,14 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: factory_bot-with
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- yubrot
|
8
|
-
autorequire:
|
9
8
|
bindir: exe
|
10
9
|
cert_chain: []
|
11
|
-
date:
|
10
|
+
date: 2025-03-15 00:00:00.000000000 Z
|
12
11
|
dependencies:
|
13
12
|
- !ruby/object:Gem::Dependency
|
14
13
|
name: factory_bot
|
@@ -52,7 +51,6 @@ metadata:
|
|
52
51
|
source_code_uri: https://github.com/yubrot/factory_bot-with
|
53
52
|
changelog_uri: https://github.com/yubrot/factory_bot-with/blob/main/CHANGELOG.md
|
54
53
|
rubygems_mfa_required: 'true'
|
55
|
-
post_install_message:
|
56
54
|
rdoc_options: []
|
57
55
|
require_paths:
|
58
56
|
- lib
|
@@ -67,8 +65,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
67
65
|
- !ruby/object:Gem::Version
|
68
66
|
version: '0'
|
69
67
|
requirements: []
|
70
|
-
rubygems_version: 3.
|
71
|
-
signing_key:
|
68
|
+
rubygems_version: 3.6.2
|
72
69
|
specification_version: 4
|
73
70
|
summary: FactoryBot extension that wraps FactoryBot::Syntax::Methods to make it a
|
74
71
|
little easier to use
|