tiny-lite-mod 0.0.1
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 +7 -0
- data/factory_bot-6.6.0/CONTRIBUTING.md +105 -0
- data/factory_bot-6.6.0/GETTING_STARTED.md +2203 -0
- data/factory_bot-6.6.0/LICENSE +19 -0
- data/factory_bot-6.6.0/NAME.md +18 -0
- data/factory_bot-6.6.0/NEWS.md +607 -0
- data/factory_bot-6.6.0/README.md +99 -0
- data/factory_bot-6.6.0/lib/factory_bot/aliases.rb +18 -0
- data/factory_bot-6.6.0/lib/factory_bot/attribute/association.rb +27 -0
- data/factory_bot-6.6.0/lib/factory_bot/attribute/dynamic.rb +25 -0
- data/factory_bot-6.6.0/lib/factory_bot/attribute/sequence.rb +16 -0
- data/factory_bot-6.6.0/lib/factory_bot/attribute.rb +27 -0
- data/factory_bot-6.6.0/lib/factory_bot/attribute_assigner.rb +168 -0
- data/factory_bot-6.6.0/lib/factory_bot/attribute_list.rb +68 -0
- data/factory_bot-6.6.0/lib/factory_bot/callback.rb +33 -0
- data/factory_bot-6.6.0/lib/factory_bot/callbacks_observer.rb +39 -0
- data/factory_bot-6.6.0/lib/factory_bot/configuration.rb +33 -0
- data/factory_bot-6.6.0/lib/factory_bot/declaration/association.rb +58 -0
- data/factory_bot-6.6.0/lib/factory_bot/declaration/dynamic.rb +28 -0
- data/factory_bot-6.6.0/lib/factory_bot/declaration/implicit.rb +38 -0
- data/factory_bot-6.6.0/lib/factory_bot/declaration.rb +23 -0
- data/factory_bot-6.6.0/lib/factory_bot/declaration_list.rb +49 -0
- data/factory_bot-6.6.0/lib/factory_bot/decorator/attribute_hash.rb +16 -0
- data/factory_bot-6.6.0/lib/factory_bot/decorator/disallows_duplicates_registry.rb +13 -0
- data/factory_bot-6.6.0/lib/factory_bot/decorator/invocation_tracker.rb +20 -0
- data/factory_bot-6.6.0/lib/factory_bot/decorator/new_constructor.rb +12 -0
- data/factory_bot-6.6.0/lib/factory_bot/decorator.rb +25 -0
- data/factory_bot-6.6.0/lib/factory_bot/definition.rb +210 -0
- data/factory_bot-6.6.0/lib/factory_bot/definition_hierarchy.rb +38 -0
- data/factory_bot-6.6.0/lib/factory_bot/definition_proxy.rb +269 -0
- data/factory_bot-6.6.0/lib/factory_bot/enum.rb +27 -0
- data/factory_bot-6.6.0/lib/factory_bot/errors.rb +28 -0
- data/factory_bot-6.6.0/lib/factory_bot/evaluation.rb +23 -0
- data/factory_bot-6.6.0/lib/factory_bot/evaluator.rb +86 -0
- data/factory_bot-6.6.0/lib/factory_bot/evaluator_class_definer.rb +20 -0
- data/factory_bot-6.6.0/lib/factory_bot/factory.rb +178 -0
- data/factory_bot-6.6.0/lib/factory_bot/factory_runner.rb +35 -0
- data/factory_bot-6.6.0/lib/factory_bot/find_definitions.rb +25 -0
- data/factory_bot-6.6.0/lib/factory_bot/internal.rb +124 -0
- data/factory_bot-6.6.0/lib/factory_bot/linter.rb +121 -0
- data/factory_bot-6.6.0/lib/factory_bot/null_factory.rb +27 -0
- data/factory_bot-6.6.0/lib/factory_bot/null_object.rb +20 -0
- data/factory_bot-6.6.0/lib/factory_bot/registry.rb +59 -0
- data/factory_bot-6.6.0/lib/factory_bot/reload.rb +7 -0
- data/factory_bot-6.6.0/lib/factory_bot/sequence.rb +197 -0
- data/factory_bot-6.6.0/lib/factory_bot/strategy/attributes_for.rb +17 -0
- data/factory_bot-6.6.0/lib/factory_bot/strategy/build.rb +21 -0
- data/factory_bot-6.6.0/lib/factory_bot/strategy/create.rb +24 -0
- data/factory_bot-6.6.0/lib/factory_bot/strategy/null.rb +15 -0
- data/factory_bot-6.6.0/lib/factory_bot/strategy/stub.rb +129 -0
- data/factory_bot-6.6.0/lib/factory_bot/strategy.rb +15 -0
- data/factory_bot-6.6.0/lib/factory_bot/strategy_syntax_method_registrar.rb +65 -0
- data/factory_bot-6.6.0/lib/factory_bot/syntax/default.rb +64 -0
- data/factory_bot-6.6.0/lib/factory_bot/syntax/methods.rb +181 -0
- data/factory_bot-6.6.0/lib/factory_bot/syntax.rb +7 -0
- data/factory_bot-6.6.0/lib/factory_bot/syntax_runner.rb +6 -0
- data/factory_bot-6.6.0/lib/factory_bot/trait.rb +39 -0
- data/factory_bot-6.6.0/lib/factory_bot/uri_manager.rb +63 -0
- data/factory_bot-6.6.0/lib/factory_bot/version.rb +3 -0
- data/factory_bot-6.6.0/lib/factory_bot.rb +117 -0
- data/tiny-lite-mod.gemspec +12 -0
- metadata +101 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
require "factory_bot/declaration/dynamic"
|
|
2
|
+
require "factory_bot/declaration/association"
|
|
3
|
+
require "factory_bot/declaration/implicit"
|
|
4
|
+
|
|
5
|
+
module FactoryBot
|
|
6
|
+
# @api private
|
|
7
|
+
class Declaration
|
|
8
|
+
attr_reader :name
|
|
9
|
+
|
|
10
|
+
def initialize(name, ignored = false)
|
|
11
|
+
@name = name
|
|
12
|
+
@ignored = ignored
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def to_attributes
|
|
16
|
+
build
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
protected
|
|
20
|
+
|
|
21
|
+
attr_reader :ignored
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
module FactoryBot
|
|
2
|
+
# @api private
|
|
3
|
+
class DeclarationList
|
|
4
|
+
include Enumerable
|
|
5
|
+
|
|
6
|
+
def initialize(name = nil)
|
|
7
|
+
@declarations = []
|
|
8
|
+
@name = name
|
|
9
|
+
@overridable = false
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def declare_attribute(declaration)
|
|
13
|
+
delete_declaration(declaration) if overridable?
|
|
14
|
+
|
|
15
|
+
@declarations << declaration
|
|
16
|
+
declaration
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def overridable
|
|
20
|
+
@overridable = true
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def attributes
|
|
24
|
+
@attributes ||= AttributeList.new(@name).tap do |list|
|
|
25
|
+
to_attributes.each do |attribute|
|
|
26
|
+
list.define_attribute(attribute)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def each(&block)
|
|
32
|
+
@declarations.each(&block)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
private
|
|
36
|
+
|
|
37
|
+
def delete_declaration(declaration)
|
|
38
|
+
@declarations.delete_if { |decl| decl.name == declaration.name }
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def to_attributes
|
|
42
|
+
@declarations.reduce([]) { |result, declaration| result + declaration.to_attributes }
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def overridable?
|
|
46
|
+
@overridable
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
module FactoryBot
|
|
2
|
+
class Decorator
|
|
3
|
+
class AttributeHash < Decorator
|
|
4
|
+
def initialize(component, attributes = [])
|
|
5
|
+
super(component)
|
|
6
|
+
@attributes = attributes
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def attributes
|
|
10
|
+
@attributes.each_with_object({}) do |attribute_name, result|
|
|
11
|
+
result[attribute_name] = @component.send(attribute_name)
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
module FactoryBot
|
|
2
|
+
class Decorator
|
|
3
|
+
class DisallowsDuplicatesRegistry < Decorator
|
|
4
|
+
def register(name, item)
|
|
5
|
+
if registered?(name)
|
|
6
|
+
raise DuplicateDefinitionError, "#{@component.name} already registered: #{name}"
|
|
7
|
+
else
|
|
8
|
+
@component.register(name, item)
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
module FactoryBot
|
|
2
|
+
class Decorator
|
|
3
|
+
class InvocationTracker < Decorator
|
|
4
|
+
def initialize(component)
|
|
5
|
+
super
|
|
6
|
+
@invoked_methods = []
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def method_missing(name, *args, &block) # rubocop:disable Style/MissingRespondToMissing
|
|
10
|
+
@invoked_methods << name
|
|
11
|
+
super
|
|
12
|
+
end
|
|
13
|
+
ruby2_keywords :method_missing if respond_to?(:ruby2_keywords, true)
|
|
14
|
+
|
|
15
|
+
def __invoked_methods__
|
|
16
|
+
@invoked_methods.uniq
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
module FactoryBot
|
|
2
|
+
class Decorator < BasicObject
|
|
3
|
+
undef_method :==
|
|
4
|
+
|
|
5
|
+
def initialize(component)
|
|
6
|
+
@component = component
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def method_missing(...) # rubocop:disable Style/MethodMissingSuper
|
|
10
|
+
@component.send(...)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def send(...)
|
|
14
|
+
__send__(...)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def respond_to_missing?(name, include_private = false)
|
|
18
|
+
@component.respond_to?(name, true) || super
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def self.const_missing(name)
|
|
22
|
+
::Object.const_get(name)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
module FactoryBot
|
|
2
|
+
# @api private
|
|
3
|
+
class Definition
|
|
4
|
+
attr_reader :defined_traits, :declarations, :name, :registered_enums, :uri_manager
|
|
5
|
+
attr_accessor :klass
|
|
6
|
+
|
|
7
|
+
def initialize(name, base_traits = [], **opts)
|
|
8
|
+
@name = name
|
|
9
|
+
@uri_manager = opts[:uri_manager]
|
|
10
|
+
@declarations = DeclarationList.new(name)
|
|
11
|
+
@callbacks = []
|
|
12
|
+
@defined_traits = Set.new
|
|
13
|
+
@registered_enums = []
|
|
14
|
+
@to_create = nil
|
|
15
|
+
@base_traits = base_traits
|
|
16
|
+
@additional_traits = []
|
|
17
|
+
@constructor = nil
|
|
18
|
+
@attributes = nil
|
|
19
|
+
@compiled = false
|
|
20
|
+
@expanded_enum_traits = false
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
delegate :declare_attribute, to: :declarations
|
|
24
|
+
|
|
25
|
+
def attributes
|
|
26
|
+
@attributes ||= AttributeList.new.tap do |attribute_list|
|
|
27
|
+
attribute_lists = aggregate_from_traits_and_self(:attributes) { declarations.attributes }
|
|
28
|
+
attribute_lists.each do |attributes|
|
|
29
|
+
attribute_list.apply_attributes attributes
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def to_create(&block)
|
|
35
|
+
if block
|
|
36
|
+
@to_create = block
|
|
37
|
+
else
|
|
38
|
+
aggregate_from_traits_and_self(:to_create) { @to_create }.last
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def constructor
|
|
43
|
+
aggregate_from_traits_and_self(:constructor) { @constructor }.last
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def callbacks
|
|
47
|
+
aggregate_from_traits_and_self(:callbacks) { @callbacks }
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def compile(klass = nil)
|
|
51
|
+
unless @compiled
|
|
52
|
+
expand_enum_traits(klass) unless klass.nil?
|
|
53
|
+
|
|
54
|
+
declarations.attributes
|
|
55
|
+
|
|
56
|
+
self.klass ||= klass
|
|
57
|
+
defined_traits.each do |defined_trait|
|
|
58
|
+
defined_trait.klass ||= klass
|
|
59
|
+
base_traits.each { |bt| bt.define_trait defined_trait }
|
|
60
|
+
additional_traits.each { |at| at.define_trait defined_trait }
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
@compiled = true
|
|
64
|
+
|
|
65
|
+
ActiveSupport::Notifications.instrument "factory_bot.compile_factory", {
|
|
66
|
+
name: name,
|
|
67
|
+
attributes: declarations.attributes,
|
|
68
|
+
traits: defined_traits,
|
|
69
|
+
class: klass || self.klass
|
|
70
|
+
}
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def overridable
|
|
75
|
+
declarations.overridable
|
|
76
|
+
self
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def inherit_traits(new_traits)
|
|
80
|
+
@base_traits += new_traits
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def append_traits(new_traits)
|
|
84
|
+
@additional_traits += new_traits
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def add_callback(callback)
|
|
88
|
+
@callbacks << callback
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def skip_create
|
|
92
|
+
@to_create = ->(instance) {}
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def define_trait(trait)
|
|
96
|
+
@defined_traits.add(trait)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def defined_traits_names
|
|
100
|
+
@defined_traits.map(&:name)
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def register_enum(enum)
|
|
104
|
+
@registered_enums << enum
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def define_constructor(&block)
|
|
108
|
+
@constructor = block
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def before(*names, &block)
|
|
112
|
+
callback(*names.map { |name| "before_#{name}" }, &block)
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def after(*names, &block)
|
|
116
|
+
callback(*names.map { |name| "after_#{name}" }, &block)
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def callback(*names, &block)
|
|
120
|
+
names.each do |name|
|
|
121
|
+
add_callback(Callback.new(name, block))
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
private
|
|
126
|
+
|
|
127
|
+
def base_traits
|
|
128
|
+
@base_traits.map { |name| trait_by_name(name) }
|
|
129
|
+
rescue KeyError => error
|
|
130
|
+
raise error_with_definition_name(error)
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
# detailed_message introduced in Ruby 3.2 for cleaner integration with
|
|
134
|
+
# did_you_mean. See https://bugs.ruby-lang.org/issues/18564
|
|
135
|
+
if KeyError.method_defined?(:detailed_message)
|
|
136
|
+
def error_with_definition_name(error)
|
|
137
|
+
message = error.message + " referenced within \"#{name}\" definition"
|
|
138
|
+
|
|
139
|
+
error.class.new(message, key: error.key, receiver: error.receiver)
|
|
140
|
+
.tap { |new_error| new_error.set_backtrace(error.backtrace) }
|
|
141
|
+
end
|
|
142
|
+
else
|
|
143
|
+
def error_with_definition_name(error)
|
|
144
|
+
message = error.message
|
|
145
|
+
message.insert(
|
|
146
|
+
message.index("\nDid you mean?") || message.length,
|
|
147
|
+
" referenced within \"#{name}\" definition"
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
error.class.new(message).tap do |new_error|
|
|
151
|
+
new_error.set_backtrace(error.backtrace)
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
def additional_traits
|
|
157
|
+
@additional_traits.map { |name| trait_by_name(name) }
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
def trait_by_name(name)
|
|
161
|
+
trait_for(name) || Internal.trait_by_name(name, klass)
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
def trait_for(name)
|
|
165
|
+
@defined_traits_by_name ||= defined_traits.each_with_object({}) { |t, memo| memo[t.name] ||= t }
|
|
166
|
+
@defined_traits_by_name[name.to_s]
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
def initialize_copy(source)
|
|
170
|
+
super
|
|
171
|
+
@attributes = nil
|
|
172
|
+
@compiled = false
|
|
173
|
+
@defined_traits_by_name = nil
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
def aggregate_from_traits_and_self(method_name, &block)
|
|
177
|
+
compile
|
|
178
|
+
|
|
179
|
+
[
|
|
180
|
+
base_traits.map(&method_name),
|
|
181
|
+
instance_exec(&block),
|
|
182
|
+
additional_traits.map(&method_name)
|
|
183
|
+
].flatten.compact
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
def expand_enum_traits(klass)
|
|
187
|
+
return if @expanded_enum_traits
|
|
188
|
+
|
|
189
|
+
if automatically_register_defined_enums?(klass)
|
|
190
|
+
automatically_register_defined_enums(klass)
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
registered_enums.each do |enum|
|
|
194
|
+
traits = enum.build_traits(klass)
|
|
195
|
+
traits.each { |trait| define_trait(trait) }
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
@expanded_enum_traits = true
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
def automatically_register_defined_enums(klass)
|
|
202
|
+
klass.defined_enums.each_key { |name| register_enum(Enum.new(name)) }
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
def automatically_register_defined_enums?(klass)
|
|
206
|
+
FactoryBot.automatically_define_enum_traits &&
|
|
207
|
+
klass.respond_to?(:defined_enums)
|
|
208
|
+
end
|
|
209
|
+
end
|
|
210
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
module FactoryBot
|
|
2
|
+
class DefinitionHierarchy
|
|
3
|
+
delegate :callbacks, :constructor, :to_create, to: Internal
|
|
4
|
+
|
|
5
|
+
def self.build_from_definition(definition)
|
|
6
|
+
build_to_create(&definition.to_create)
|
|
7
|
+
build_constructor(&definition.constructor)
|
|
8
|
+
add_callbacks definition.callbacks
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def self.add_callbacks(callbacks)
|
|
12
|
+
if callbacks.any?
|
|
13
|
+
define_method :callbacks do
|
|
14
|
+
super() + callbacks
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
private_class_method :add_callbacks
|
|
19
|
+
|
|
20
|
+
def self.build_constructor(&block)
|
|
21
|
+
if block
|
|
22
|
+
define_method(:constructor) do
|
|
23
|
+
block
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
private_class_method :build_constructor
|
|
28
|
+
|
|
29
|
+
def self.build_to_create(&block)
|
|
30
|
+
if block
|
|
31
|
+
define_method(:to_create) do
|
|
32
|
+
block
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
private_class_method :build_to_create
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
module FactoryBot
|
|
2
|
+
class DefinitionProxy
|
|
3
|
+
UNPROXIED_METHODS = %w[
|
|
4
|
+
__send__
|
|
5
|
+
__id__
|
|
6
|
+
nil?
|
|
7
|
+
send
|
|
8
|
+
object_id
|
|
9
|
+
extend
|
|
10
|
+
instance_eval
|
|
11
|
+
initialize
|
|
12
|
+
block_given?
|
|
13
|
+
raise
|
|
14
|
+
caller
|
|
15
|
+
method
|
|
16
|
+
].freeze
|
|
17
|
+
|
|
18
|
+
(instance_methods + private_instance_methods).each do |method|
|
|
19
|
+
undef_method(method) unless UNPROXIED_METHODS.include?(method.to_s)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
delegate :before, :after, :callback, to: :@definition
|
|
23
|
+
|
|
24
|
+
attr_reader :child_factories
|
|
25
|
+
|
|
26
|
+
def initialize(definition, ignore = false)
|
|
27
|
+
@definition = definition
|
|
28
|
+
@ignore = ignore
|
|
29
|
+
@child_factories = []
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def singleton_method_added(name)
|
|
33
|
+
message = "Defining methods in blocks (trait or factory) is not supported (#{name})"
|
|
34
|
+
raise FactoryBot::MethodDefinitionError, message
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Adds an attribute to the factory.
|
|
38
|
+
# The attribute value will be generated "lazily"
|
|
39
|
+
# by calling the block whenever an instance is generated.
|
|
40
|
+
# The block will not be called if the
|
|
41
|
+
# attribute is overridden for a specific instance.
|
|
42
|
+
#
|
|
43
|
+
# Arguments:
|
|
44
|
+
# * name: +Symbol+ or +String+
|
|
45
|
+
# The name of this attribute. This will be assigned using "name=" for
|
|
46
|
+
# generated instances.
|
|
47
|
+
def add_attribute(name, &block)
|
|
48
|
+
declaration = Declaration::Dynamic.new(name, @ignore, block)
|
|
49
|
+
@definition.declare_attribute(declaration)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def transient(&block)
|
|
53
|
+
proxy = DefinitionProxy.new(@definition, true)
|
|
54
|
+
proxy.instance_eval(&block)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Calls add_attribute using the missing method name as the name of the
|
|
58
|
+
# attribute, so that:
|
|
59
|
+
#
|
|
60
|
+
# factory :user do
|
|
61
|
+
# name { 'Billy Idol' }
|
|
62
|
+
# end
|
|
63
|
+
#
|
|
64
|
+
# and:
|
|
65
|
+
#
|
|
66
|
+
# factory :user do
|
|
67
|
+
# add_attribute(:name) { 'Billy Idol' }
|
|
68
|
+
# end
|
|
69
|
+
#
|
|
70
|
+
# are equivalent.
|
|
71
|
+
#
|
|
72
|
+
# If no argument or block is given, factory_bot will first look for an
|
|
73
|
+
# association, then for a sequence, and finally for a trait with the same
|
|
74
|
+
# name. This means that given an "admin" trait, an "email" sequence, and an
|
|
75
|
+
# "account" factory:
|
|
76
|
+
#
|
|
77
|
+
# factory :user, traits: [:admin] do
|
|
78
|
+
# email { generate(:email) }
|
|
79
|
+
# association :account
|
|
80
|
+
# end
|
|
81
|
+
#
|
|
82
|
+
# and:
|
|
83
|
+
#
|
|
84
|
+
# factory :user do
|
|
85
|
+
# admin
|
|
86
|
+
# email
|
|
87
|
+
# account
|
|
88
|
+
# end
|
|
89
|
+
#
|
|
90
|
+
# are equivalent.
|
|
91
|
+
def method_missing(name, *args, &block) # rubocop:disable Style/MissingRespondToMissing
|
|
92
|
+
association_options = args.first
|
|
93
|
+
|
|
94
|
+
if association_options.nil?
|
|
95
|
+
__declare_attribute__(name, block)
|
|
96
|
+
elsif __valid_association_options?(association_options)
|
|
97
|
+
association(name, association_options, &block)
|
|
98
|
+
else
|
|
99
|
+
raise NoMethodError.new(<<~MSG)
|
|
100
|
+
undefined method '#{name}' in '#{@definition.name}' factory
|
|
101
|
+
Did you mean? '#{name} { #{association_options.inspect} }'
|
|
102
|
+
MSG
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# Adds an attribute that will have unique values generated by a sequence with
|
|
107
|
+
# a specified format.
|
|
108
|
+
#
|
|
109
|
+
# The result of:
|
|
110
|
+
# factory :user do
|
|
111
|
+
# sequence(:email) { |n| "person#{n}@example.com" }
|
|
112
|
+
# end
|
|
113
|
+
#
|
|
114
|
+
# Is equal to:
|
|
115
|
+
# sequence(:email) { |n| "person#{n}@example.com" }
|
|
116
|
+
#
|
|
117
|
+
# factory :user do
|
|
118
|
+
# email { FactoryBot.generate(:email) }
|
|
119
|
+
# end
|
|
120
|
+
#
|
|
121
|
+
# Except that no globally available sequence will be defined.
|
|
122
|
+
def sequence(name, *args, &block)
|
|
123
|
+
options = args.extract_options!
|
|
124
|
+
options[:uri_paths] = @definition.uri_manager.to_a
|
|
125
|
+
args << options
|
|
126
|
+
|
|
127
|
+
new_sequence = Sequence.new(name, *args, &block)
|
|
128
|
+
registered_sequence = __fetch_or_register_sequence(new_sequence)
|
|
129
|
+
add_attribute(name) { increment_sequence(registered_sequence) }
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
# Adds an attribute that builds an association. The associated instance will
|
|
133
|
+
# be built using the same build strategy as the parent instance.
|
|
134
|
+
#
|
|
135
|
+
# Example:
|
|
136
|
+
# factory :user do
|
|
137
|
+
# name 'Joey'
|
|
138
|
+
# end
|
|
139
|
+
#
|
|
140
|
+
# factory :post do
|
|
141
|
+
# association :author, factory: :user
|
|
142
|
+
# end
|
|
143
|
+
#
|
|
144
|
+
# Arguments:
|
|
145
|
+
# * name: +Symbol+
|
|
146
|
+
# The name of this attribute.
|
|
147
|
+
# * options: +Hash+
|
|
148
|
+
#
|
|
149
|
+
# Options:
|
|
150
|
+
# * factory: +Symbol+ or +String+
|
|
151
|
+
# The name of the factory to use when building the associated instance.
|
|
152
|
+
# If no name is given, the name of the attribute is assumed to be the
|
|
153
|
+
# name of the factory. For example, a "user" association will by
|
|
154
|
+
# default use the "user" factory.
|
|
155
|
+
def association(name, *options)
|
|
156
|
+
if block_given?
|
|
157
|
+
raise AssociationDefinitionError.new(
|
|
158
|
+
"Unexpected block passed to '#{name}' association " \
|
|
159
|
+
"in '#{@definition.name}' factory"
|
|
160
|
+
)
|
|
161
|
+
else
|
|
162
|
+
declaration = Declaration::Association.new(name, *options)
|
|
163
|
+
@definition.declare_attribute(declaration)
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
def to_create(&block)
|
|
168
|
+
@definition.to_create(&block)
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
def skip_create
|
|
172
|
+
@definition.skip_create
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
def factory(name, options = {}, &block)
|
|
176
|
+
child_factories << [name, options, block]
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
def trait(name, &block)
|
|
180
|
+
@definition.define_trait(Trait.new(name, uri_paths: @definition.uri_manager.to_a, &block))
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
# Creates traits for enumerable values.
|
|
184
|
+
#
|
|
185
|
+
# Example:
|
|
186
|
+
# factory :task do
|
|
187
|
+
# traits_for_enum :status, [:started, :finished]
|
|
188
|
+
# end
|
|
189
|
+
#
|
|
190
|
+
# Equivalent to:
|
|
191
|
+
# factory :task do
|
|
192
|
+
# trait :started do
|
|
193
|
+
# status { :started }
|
|
194
|
+
# end
|
|
195
|
+
#
|
|
196
|
+
# trait :finished do
|
|
197
|
+
# status { :finished }
|
|
198
|
+
# end
|
|
199
|
+
# end
|
|
200
|
+
#
|
|
201
|
+
# Example:
|
|
202
|
+
# factory :task do
|
|
203
|
+
# traits_for_enum :status, {started: 1, finished: 2}
|
|
204
|
+
# end
|
|
205
|
+
#
|
|
206
|
+
# Example:
|
|
207
|
+
# class Task
|
|
208
|
+
# def statuses
|
|
209
|
+
# {started: 1, finished: 2}
|
|
210
|
+
# end
|
|
211
|
+
# end
|
|
212
|
+
#
|
|
213
|
+
# factory :task do
|
|
214
|
+
# traits_for_enum :status
|
|
215
|
+
# end
|
|
216
|
+
#
|
|
217
|
+
# Both equivalent to:
|
|
218
|
+
# factory :task do
|
|
219
|
+
# trait :started do
|
|
220
|
+
# status { 1 }
|
|
221
|
+
# end
|
|
222
|
+
#
|
|
223
|
+
# trait :finished do
|
|
224
|
+
# status { 2 }
|
|
225
|
+
# end
|
|
226
|
+
# end
|
|
227
|
+
#
|
|
228
|
+
#
|
|
229
|
+
# Arguments:
|
|
230
|
+
# attribute_name: +Symbol+ or +String+
|
|
231
|
+
# the name of the attribute these traits will set the value of
|
|
232
|
+
# values: +Array+, +Hash+, or other +Enumerable+
|
|
233
|
+
# An array of trait names, or a mapping of trait names to values for
|
|
234
|
+
# those traits. When this argument is not provided, factory_bot will
|
|
235
|
+
# attempt to get the values by calling the pluralized `attribute_name`
|
|
236
|
+
# class method.
|
|
237
|
+
def traits_for_enum(attribute_name, values = nil)
|
|
238
|
+
@definition.register_enum(Enum.new(attribute_name, values))
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
def initialize_with(&block)
|
|
242
|
+
@definition.define_constructor(&block)
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
private
|
|
246
|
+
|
|
247
|
+
def __declare_attribute__(name, block)
|
|
248
|
+
if block.nil?
|
|
249
|
+
declaration = Declaration::Implicit.new(name, @definition, @ignore)
|
|
250
|
+
@definition.declare_attribute(declaration)
|
|
251
|
+
else
|
|
252
|
+
add_attribute(name, &block)
|
|
253
|
+
end
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
def __valid_association_options?(options)
|
|
257
|
+
options.respond_to?(:has_key?) && options.has_key?(:factory)
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
##
|
|
261
|
+
# If the inline sequence has already been registered by a parent,
|
|
262
|
+
# return that one, otherwise register and return the given sequence
|
|
263
|
+
#
|
|
264
|
+
def __fetch_or_register_sequence(sequence)
|
|
265
|
+
FactoryBot::Sequence.find_by_uri(sequence.uri_manager.first) ||
|
|
266
|
+
FactoryBot::Internal.register_inline_sequence(sequence)
|
|
267
|
+
end
|
|
268
|
+
end
|
|
269
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
module FactoryBot
|
|
2
|
+
# @api private
|
|
3
|
+
class Enum
|
|
4
|
+
def initialize(attribute_name, values = nil)
|
|
5
|
+
@attribute_name = attribute_name
|
|
6
|
+
@values = values
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def build_traits(klass)
|
|
10
|
+
enum_values(klass).map do |trait_name, value|
|
|
11
|
+
build_trait(trait_name, @attribute_name, value || trait_name)
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
private
|
|
16
|
+
|
|
17
|
+
def enum_values(klass)
|
|
18
|
+
@values || klass.send(@attribute_name.to_s.pluralize)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def build_trait(trait_name, attribute_name, value)
|
|
22
|
+
Trait.new(trait_name) do
|
|
23
|
+
add_attribute(attribute_name) { value }
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|