factory_bot-with 0.1.0 → 0.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a279f1170ba696ac48614f1c95572bf4be5a9b3f5ac5e47a3574813deafd5623
4
- data.tar.gz: dddb6e8f841108fd70a80d509ea847a9daf6b0613111bf9977c8b79a6e32bf20
3
+ metadata.gz: 01b5be917f74ffbdc5643be7bb5f9c9e7f1009484f688a8442aed6dda8dc5a0b
4
+ data.tar.gz: d773865f81b4aad3e87dea573db938b5393f0ecc988b5810b827741051ee6864
5
5
  SHA512:
6
- metadata.gz: 2dc2904bb72bee299282e42f9daa0ba697e7c4eb7febd3475697ff0db2df89c03aa71c5bc55e2e97d2a786a3f3449b6666d68b643874a70bc32a5f6ef0a379ee
7
- data.tar.gz: 3b322dbad72231b9e16e97113a3a300db5a88a90d2a67c06ef026711881c2de52f48ca0326810be0ab3e1ce7f57ca56d238a1070d6a78eca2ddf5d667dd226ea
6
+ metadata.gz: 93c900afe0c21747d9837a5c8e1b31b11a7ae3e127873cdf86f43f5f83fac4ba10be0295e7b43542d3399a78be377fd240f57a9251a8433471015767170d96a5
7
+ data.tar.gz: 1af4669b1afb19783332b2bed70d7cb76d210bb205766dcc3aae06bd07de0a4a614da1aadc0841e6cca0bf8c3b3965241a05703a898172a0c575ddcd93f8d273
data/CHANGELOG.md CHANGED
@@ -1,5 +1,10 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.2.0] - 2024-11-29
4
+
5
+ - Fixed: Fixed an incorrect factory resolution problem after factory names autocompletion
6
+ - Added: Smarter interpretation of positional arguments passed to factory methods
7
+
3
8
  ## [0.1.0] - 2024-11-27
4
9
 
5
10
  - Initial release
data/README.md CHANGED
@@ -1,5 +1,8 @@
1
1
  # FactoryBot::With
2
2
 
3
+ [![](https://badge.fury.io/rb/factory_bot-with.svg)](https://badge.fury.io/rb/factory_bot-with)
4
+ [![](https://github.com/yubrot/factory_bot-with/actions/workflows/main.yml/badge.svg)](https://github.com/yubrot/factory_bot-with/actions/workflows/main.yml)
5
+
3
6
  FactoryBot::With is a FactoryBot extension that wraps `FactoryBot::Syntax::Methods` to make it a little easier to use.
4
7
 
5
8
  For example, with these factories:
@@ -68,6 +71,16 @@ build_stubbed.foo(...)
68
71
  create_list.foo(10, ...)
69
72
  ```
70
73
 
74
+ ### Smarter interpretation of positional arguments
75
+
76
+ FactoryBot::With adjusts the behavior of factory methods to accept `Hash`, `Array`, and falsy values (`false` or `nil`) as positional arguments.
77
+
78
+ ```ruby
79
+ create.foo({ title: "Recipe" }, is_new && %i[latest hot])
80
+ #=> create(:foo, :latest, :hot, title: "Recipe") if is_new
81
+ # create(:foo, title: "Recipe") otherwise
82
+ ```
83
+
71
84
  ### `with`, `with_pair`, and `with_list` operator
72
85
 
73
86
  FactoryBot::With provides a new operator `with` (and its family).
@@ -18,14 +18,7 @@ module FactoryBot
18
18
  define_method(method_name) do |factory = nil, *args, **kwargs, &block|
19
19
  return Proxy.new(self, __method__) unless factory
20
20
 
21
- with =
22
- if factory.is_a? With
23
- factory.merge(With.new(variation, factory.factory_name, *args, **kwargs, &block))
24
- else
25
- With.new(variation, factory, *args, **kwargs, &block)
26
- end
27
-
28
- with.instantiate(build_strategy)
21
+ With.build(variation, factory, *args, **kwargs, &block).instantiate(build_strategy)
29
22
  end
30
23
  end
31
24
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module FactoryBot
4
4
  class With
5
- VERSION = "0.1.0"
5
+ VERSION = "0.2.0"
6
6
  end
7
7
  end
@@ -15,25 +15,32 @@ module FactoryBot
15
15
  attr_reader :factory_name
16
16
  # @return [Array<With>]
17
17
  attr_reader :withes
18
- # @return [Array<Object>]
19
- attr_reader :args
18
+ # @return [Array<Numeric, Symbol>] Numeric is also treated as a trait for convenience
19
+ attr_reader :traits
20
20
  # @return [{Symbol => Object}]
21
- attr_reader :kwargs
21
+ attr_reader :attrs
22
22
  # @return [Proc, nil]
23
23
  attr_reader :block
24
24
 
25
25
  # @!visibility private
26
- def initialize(variation, factory_name, *args, **kwargs, &block)
26
+ def initialize(variation, factory_name, withes: [], traits: [], attrs: {}, &block)
27
+ raise ArgumentError unless %i[unit pair list].include? variation
28
+ raise TypeError unless factory_name.is_a? Symbol
29
+ raise TypeError unless withes.is_a?(Array) && withes.all? { _1.is_a? self.class }
30
+ raise TypeError unless traits.is_a?(Array) && traits.all? { _1.is_a?(Symbol) || _1.is_a?(Numeric) }
31
+ raise TypeError unless attrs.is_a?(Hash) && attrs.keys.all? { _1.is_a? Symbol }
32
+
27
33
  @variation = variation
28
34
  @factory_name = factory_name
29
- @withes, @args = args.partition { _1.is_a? self.class }
30
- @kwargs = kwargs
35
+ @withes = withes
36
+ @traits = traits
37
+ @attrs = attrs
31
38
  @block = block
32
39
  end
33
40
 
34
41
  # @!visibility private
35
42
  # @return [Boolean]
36
- def plain? = withes.empty? && args.empty? && kwargs.empty? && block.nil?
43
+ def plain? = withes.empty? && traits.empty? && attrs.empty? && block.nil?
37
44
 
38
45
  # @!visibility private
39
46
  # @param other [With]
@@ -49,8 +56,9 @@ module FactoryBot
49
56
  self.class.new(
50
57
  variation,
51
58
  factory_name,
52
- *args, *other.args, *withes, *other.withes,
53
- **kwargs, **other.kwargs,
59
+ withes: [*withes, *other.withes],
60
+ traits: [*traits, *other.traits],
61
+ attrs: { **attrs, **other.attrs },
54
62
  &self.class.merge_block(block, other.block)
55
63
  )
56
64
  end
@@ -63,20 +71,20 @@ module FactoryBot
63
71
  return self if build_strategy == :with
64
72
 
65
73
  factory_bot_method = Methods::VARIATIONS[variation][build_strategy]
66
- factory_name, kwargs =
74
+ factory_name, attrs =
67
75
  if ancestors
68
- kwargs = @kwargs.dup
76
+ attrs = @attrs.dup
69
77
  factory_name = AssocInfo.autocomplete_fully_qualified_factory_name(ancestors, @factory_name)
70
- AssocInfo.get(factory_name).perform_automatic_association_resolution(ancestors, kwargs)
71
- [factory_name, kwargs]
78
+ AssocInfo.get(factory_name).perform_automatic_association_resolution(ancestors, attrs)
79
+ [factory_name, attrs]
72
80
  else
73
- [@factory_name, @kwargs]
81
+ [@factory_name, @attrs]
74
82
  end
75
- result = FactoryBot.__send__(factory_bot_method, factory_name, *args, **kwargs, &block)
83
+ result = FactoryBot.__send__(factory_bot_method, factory_name, *traits, **attrs, &block)
76
84
 
77
85
  unless withes.empty?
78
86
  parents = variation == :unit ? [result] : result
79
- assoc_info = AssocInfo.get(@factory_name)
87
+ assoc_info = AssocInfo.get(factory_name)
80
88
  parents.each do |parent|
81
89
  ancestors_for_children = [[assoc_info, parent], *ancestors || []]
82
90
  withes.each { _1.instantiate(build_strategy, ancestors_for_children) }
@@ -86,17 +94,52 @@ module FactoryBot
86
94
  result
87
95
  end
88
96
 
89
- # @!visibility private
90
- # @param first [Proc, nil]
91
- # @param second [Proc, nil]
92
- # @return [Proc, nil]
93
- def self.merge_block(first, second)
94
- return first unless second
95
- return second unless first
97
+ class << self
98
+ # @!visibility private
99
+ # @param variation [:unit, :pair, :list]
100
+ # @param factory [Symbol, With]
101
+ # @param args [Array<Object>]
102
+ # @param kwargs [{Symbol => Object}]
103
+ def build(variation, factory, *, **, &)
104
+ return factory.merge(build(variation, factory.factory_name, *, **, &)) if factory.is_a? self
105
+
106
+ with = new(variation, factory, &)
107
+ insert_args!(with, *)
108
+ with.attrs.merge!(**)
109
+ with
110
+ end
96
111
 
97
- lambda do |*args|
98
- first.call(*args)
99
- second.call(*args)
112
+ def insert_args!(with, *args)
113
+ args.each do |arg|
114
+ case arg
115
+ when self
116
+ with.withes << arg
117
+ when Symbol, Numeric
118
+ with.traits << arg
119
+ when Array
120
+ insert_args!(with, *arg)
121
+ when Hash
122
+ with.attrs.merge!(arg)
123
+ when false, nil
124
+ # Ignored. This behavior is useful for conditional arguments like `is_premium && :premium`
125
+ else
126
+ raise ArgumentError, "Unsupported type for factory argument: #{arg}"
127
+ end
128
+ end
129
+ end
130
+
131
+ # @!visibility private
132
+ # @param first [Proc, nil]
133
+ # @param second [Proc, nil]
134
+ # @return [Proc, nil]
135
+ def merge_block(first, second)
136
+ return first unless second
137
+ return second unless first
138
+
139
+ lambda do |*args|
140
+ first.call(*args)
141
+ second.call(*args)
142
+ end
100
143
  end
101
144
  end
102
145
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: factory_bot-with
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - yubrot
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-11-27 00:00:00.000000000 Z
11
+ date: 2024-11-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: factory_bot
@@ -67,7 +67,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
69
  requirements: []
70
- rubygems_version: 3.5.23
70
+ rubygems_version: 3.5.22
71
71
  signing_key:
72
72
  specification_version: 4
73
73
  summary: FactoryBot extension that wraps FactoryBot::Syntax::Methods to make it a