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,28 @@
|
|
|
1
|
+
module FactoryBot
|
|
2
|
+
# Raised when a factory is defined that attempts to instantiate itself.
|
|
3
|
+
class AssociationDefinitionError < RuntimeError; end
|
|
4
|
+
|
|
5
|
+
# Raised when a trait is defined that references itself.
|
|
6
|
+
class TraitDefinitionError < RuntimeError; end
|
|
7
|
+
|
|
8
|
+
# Raised when a callback is defined that has an invalid name
|
|
9
|
+
class InvalidCallbackNameError < RuntimeError; end
|
|
10
|
+
|
|
11
|
+
# Raised when a factory is defined with the same name as a previously-defined factory.
|
|
12
|
+
class DuplicateDefinitionError < RuntimeError; end
|
|
13
|
+
|
|
14
|
+
# Raised when attempting to register a sequence from a dynamic attribute block
|
|
15
|
+
class SequenceAbuseError < RuntimeError; end
|
|
16
|
+
|
|
17
|
+
# Raised when defining an attribute twice in the same factory
|
|
18
|
+
class AttributeDefinitionError < RuntimeError; end
|
|
19
|
+
|
|
20
|
+
# Raised when attempting to pass a block to an association definition
|
|
21
|
+
class AssociationDefinitionError < RuntimeError; end
|
|
22
|
+
|
|
23
|
+
# Raised when a method is defined in a factory or trait with arguments
|
|
24
|
+
class MethodDefinitionError < RuntimeError; end
|
|
25
|
+
|
|
26
|
+
# Raised when any factory is considered invalid
|
|
27
|
+
class InvalidFactoryError < RuntimeError; end
|
|
28
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
module FactoryBot
|
|
2
|
+
class Evaluation
|
|
3
|
+
def initialize(evaluator, attribute_assigner, to_create, observer)
|
|
4
|
+
@evaluator = evaluator
|
|
5
|
+
@attribute_assigner = attribute_assigner
|
|
6
|
+
@to_create = to_create
|
|
7
|
+
@observer = observer
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
delegate :object, :hash, to: :@attribute_assigner
|
|
11
|
+
|
|
12
|
+
def create(result_instance)
|
|
13
|
+
case @to_create.arity
|
|
14
|
+
when 2 then @to_create[result_instance, @evaluator]
|
|
15
|
+
else @to_create[result_instance]
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def notify(name, result_instance)
|
|
20
|
+
@observer.update(name, result_instance)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
require "active_support/core_ext/class/attribute"
|
|
2
|
+
|
|
3
|
+
module FactoryBot
|
|
4
|
+
# @api private
|
|
5
|
+
class Evaluator
|
|
6
|
+
class_attribute :attribute_lists
|
|
7
|
+
|
|
8
|
+
private_instance_methods.each do |method|
|
|
9
|
+
undef_method(method) unless method.match?(/^__|initialize/)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def initialize(build_strategy, overrides = {})
|
|
13
|
+
@build_strategy = build_strategy
|
|
14
|
+
@overrides = overrides
|
|
15
|
+
@cached_attributes = overrides
|
|
16
|
+
@instance = nil
|
|
17
|
+
|
|
18
|
+
@overrides.each do |name, value|
|
|
19
|
+
singleton_class.define_attribute(name) { value }
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def association(factory_name, *traits_and_overrides)
|
|
24
|
+
overrides = traits_and_overrides.extract_options!
|
|
25
|
+
strategy_override = overrides.fetch(:strategy) {
|
|
26
|
+
FactoryBot.use_parent_strategy ? @build_strategy.to_sym : :create
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
traits_and_overrides += [overrides.except(:strategy)]
|
|
30
|
+
|
|
31
|
+
runner = FactoryRunner.new(factory_name, strategy_override, traits_and_overrides)
|
|
32
|
+
@build_strategy.association(runner)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
attr_accessor :instance
|
|
36
|
+
|
|
37
|
+
def method_missing(method_name, ...)
|
|
38
|
+
if @instance.respond_to?(method_name)
|
|
39
|
+
@instance.send(method_name, ...)
|
|
40
|
+
else
|
|
41
|
+
SyntaxRunner.new.send(method_name, ...)
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def respond_to_missing?(method_name, _include_private = false)
|
|
46
|
+
@instance.respond_to?(method_name) || SyntaxRunner.new.respond_to?(method_name)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def __override_names__
|
|
50
|
+
@overrides.keys
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def increment_sequence(sequence, scope: self)
|
|
54
|
+
value = sequence.next(scope)
|
|
55
|
+
|
|
56
|
+
raise if value.respond_to?(:start_with?) && value.start_with?("#<FactoryBot::Declaration")
|
|
57
|
+
|
|
58
|
+
value
|
|
59
|
+
rescue
|
|
60
|
+
raise ArgumentError, "Sequence '#{sequence.uri_manager.first}' failed to " \
|
|
61
|
+
"return a value. Perhaps it needs a scope to operate? (scope: <object>)"
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def self.attribute_list
|
|
65
|
+
AttributeList.new.tap do |list|
|
|
66
|
+
attribute_lists.each do |attribute_list|
|
|
67
|
+
list.apply_attributes attribute_list.to_a
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def self.define_attribute(name, &block)
|
|
73
|
+
if instance_methods(false).include?(name) || private_instance_methods(false).include?(name)
|
|
74
|
+
undef_method(name)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
define_method(name) do
|
|
78
|
+
if @cached_attributes.key?(name)
|
|
79
|
+
@cached_attributes[name]
|
|
80
|
+
else
|
|
81
|
+
@cached_attributes[name] = instance_exec(&block)
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
module FactoryBot
|
|
2
|
+
# @api private
|
|
3
|
+
class EvaluatorClassDefiner
|
|
4
|
+
def initialize(attributes, parent_class)
|
|
5
|
+
@parent_class = parent_class
|
|
6
|
+
@attributes = attributes
|
|
7
|
+
|
|
8
|
+
attributes.each do |attribute|
|
|
9
|
+
evaluator_class.define_attribute(attribute.name, &attribute.to_proc)
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def evaluator_class
|
|
14
|
+
@evaluator_class ||= Class.new(@parent_class).tap do |klass|
|
|
15
|
+
klass.attribute_lists ||= []
|
|
16
|
+
klass.attribute_lists += [@attributes]
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
require "active_support/core_ext/hash/keys"
|
|
2
|
+
require "active_support/inflector"
|
|
3
|
+
|
|
4
|
+
module FactoryBot
|
|
5
|
+
# @api private
|
|
6
|
+
class Factory
|
|
7
|
+
attr_reader :name, :definition
|
|
8
|
+
|
|
9
|
+
def initialize(name, options = {})
|
|
10
|
+
assert_valid_options(options)
|
|
11
|
+
@name = name.respond_to?(:to_sym) ? name.to_sym : name.to_s.underscore.to_sym
|
|
12
|
+
@parent = options[:parent]
|
|
13
|
+
@aliases = options[:aliases] || []
|
|
14
|
+
@class_name = options[:class]
|
|
15
|
+
@uri_manager = FactoryBot::UriManager.new(names)
|
|
16
|
+
@definition = Definition.new(@name, options[:traits] || [], uri_manager: @uri_manager)
|
|
17
|
+
@compiled = false
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
delegate :add_callback, :declare_attribute, :to_create, :define_trait, :constructor,
|
|
21
|
+
:defined_traits, :defined_traits_names, :inherit_traits, :append_traits,
|
|
22
|
+
to: :@definition
|
|
23
|
+
|
|
24
|
+
def build_class
|
|
25
|
+
@build_class ||= if class_name.is_a? Class
|
|
26
|
+
class_name
|
|
27
|
+
elsif class_name.to_s.safe_constantize
|
|
28
|
+
class_name.to_s.safe_constantize
|
|
29
|
+
else
|
|
30
|
+
class_name.to_s.camelize.constantize
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def run(build_strategy, overrides, &block)
|
|
35
|
+
block ||= ->(result) { result }
|
|
36
|
+
|
|
37
|
+
compile
|
|
38
|
+
|
|
39
|
+
strategy = Strategy.lookup_strategy(build_strategy).new
|
|
40
|
+
|
|
41
|
+
evaluator = evaluator_class.new(strategy, overrides.symbolize_keys)
|
|
42
|
+
attribute_assigner = AttributeAssigner.new(evaluator, build_class, &compiled_constructor)
|
|
43
|
+
|
|
44
|
+
observer = CallbacksObserver.new(callbacks, evaluator)
|
|
45
|
+
evaluation = Evaluation.new(evaluator, attribute_assigner, compiled_to_create, observer)
|
|
46
|
+
|
|
47
|
+
evaluation.notify(:before_all, nil)
|
|
48
|
+
instance = strategy.result(evaluation).tap(&block)
|
|
49
|
+
evaluation.notify(:after_all, instance)
|
|
50
|
+
|
|
51
|
+
instance
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def human_names
|
|
55
|
+
names.map { |name| name.to_s.humanize.downcase }
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def associations
|
|
59
|
+
evaluator_class.attribute_list.associations
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# Names for this factory, including aliases.
|
|
63
|
+
#
|
|
64
|
+
# Example:
|
|
65
|
+
#
|
|
66
|
+
# factory :user, aliases: [:author] do
|
|
67
|
+
# # ...
|
|
68
|
+
# end
|
|
69
|
+
#
|
|
70
|
+
# FactoryBot.create(:author).class
|
|
71
|
+
# # => User
|
|
72
|
+
#
|
|
73
|
+
# Because an attribute defined without a value or block will build an
|
|
74
|
+
# association with the same name, this allows associations to be defined
|
|
75
|
+
# without factories, such as:
|
|
76
|
+
#
|
|
77
|
+
# factory :user, aliases: [:author] do
|
|
78
|
+
# # ...
|
|
79
|
+
# end
|
|
80
|
+
#
|
|
81
|
+
# factory :post do
|
|
82
|
+
# author
|
|
83
|
+
# end
|
|
84
|
+
#
|
|
85
|
+
# FactoryBot.create(:post).author.class
|
|
86
|
+
# # => User
|
|
87
|
+
def names
|
|
88
|
+
[name] + @aliases
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def compile
|
|
92
|
+
unless @compiled
|
|
93
|
+
parent.compile
|
|
94
|
+
inherit_parent_traits
|
|
95
|
+
@definition.compile(build_class)
|
|
96
|
+
build_hierarchy
|
|
97
|
+
@compiled = true
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def with_traits(traits)
|
|
102
|
+
clone.tap do |factory_with_traits|
|
|
103
|
+
factory_with_traits.append_traits traits
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
protected
|
|
108
|
+
|
|
109
|
+
def class_name
|
|
110
|
+
@class_name || parent.class_name || name
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def evaluator_class
|
|
114
|
+
@evaluator_class ||= EvaluatorClassDefiner.new(attributes, parent.evaluator_class).evaluator_class
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def attributes
|
|
118
|
+
compile
|
|
119
|
+
AttributeList.new(@name).tap do |list|
|
|
120
|
+
list.apply_attributes definition.attributes
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def hierarchy_class
|
|
125
|
+
@hierarchy_class ||= Class.new(parent.hierarchy_class)
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def hierarchy_instance
|
|
129
|
+
@hierarchy_instance ||= hierarchy_class.new
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def build_hierarchy
|
|
133
|
+
hierarchy_class.build_from_definition definition
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def callbacks
|
|
137
|
+
hierarchy_instance.callbacks
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def compiled_to_create
|
|
141
|
+
hierarchy_instance.to_create
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def compiled_constructor
|
|
145
|
+
hierarchy_instance.constructor
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
private
|
|
149
|
+
|
|
150
|
+
def assert_valid_options(options)
|
|
151
|
+
options.assert_valid_keys(:class, :parent, :aliases, :traits)
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def parent
|
|
155
|
+
if @parent
|
|
156
|
+
FactoryBot::Internal.factory_by_name(@parent)
|
|
157
|
+
else
|
|
158
|
+
NullFactory.new
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
def inherit_parent_traits
|
|
163
|
+
parent.defined_traits.each do |trait|
|
|
164
|
+
next if defined_traits_names.include?(trait.name)
|
|
165
|
+
define_trait(trait.clone)
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
def initialize_copy(source)
|
|
170
|
+
super
|
|
171
|
+
@definition = @definition.clone
|
|
172
|
+
@evaluator_class = nil
|
|
173
|
+
@hierarchy_class = nil
|
|
174
|
+
@hierarchy_instance = nil
|
|
175
|
+
@compiled = false
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
module FactoryBot
|
|
2
|
+
class FactoryRunner
|
|
3
|
+
def initialize(name, strategy, traits_and_overrides)
|
|
4
|
+
@name = name
|
|
5
|
+
@strategy = strategy
|
|
6
|
+
|
|
7
|
+
@overrides = traits_and_overrides.extract_options!
|
|
8
|
+
@traits = traits_and_overrides
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def run(runner_strategy = @strategy, &block)
|
|
12
|
+
factory = FactoryBot::Internal.factory_by_name(@name)
|
|
13
|
+
|
|
14
|
+
factory.compile
|
|
15
|
+
|
|
16
|
+
if @traits.any?
|
|
17
|
+
factory = factory.with_traits(@traits)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
instrumentation_payload = {
|
|
21
|
+
name: @name,
|
|
22
|
+
strategy: runner_strategy,
|
|
23
|
+
traits: @traits,
|
|
24
|
+
overrides: @overrides,
|
|
25
|
+
factory: factory
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
ActiveSupport::Notifications.instrument("factory_bot.before_run_factory", instrumentation_payload)
|
|
29
|
+
|
|
30
|
+
ActiveSupport::Notifications.instrument("factory_bot.run_factory", instrumentation_payload) do
|
|
31
|
+
factory.run(runner_strategy, @overrides, &block)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
module FactoryBot
|
|
2
|
+
class << self
|
|
3
|
+
# An Array of strings specifying locations that should be searched for
|
|
4
|
+
# factory definitions. By default, factory_bot will attempt to require
|
|
5
|
+
# "factories.rb", "factories/**/*.rb", "test/factories.rb",
|
|
6
|
+
# "test/factories/**.rb", "spec/factories.rb", and "spec/factories/**.rb".
|
|
7
|
+
attr_accessor :definition_file_paths
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
self.definition_file_paths = %w[factories test/factories spec/factories]
|
|
11
|
+
|
|
12
|
+
def self.find_definitions
|
|
13
|
+
absolute_definition_file_paths = definition_file_paths.map { |path| File.expand_path(path) }
|
|
14
|
+
|
|
15
|
+
absolute_definition_file_paths.uniq.each do |path|
|
|
16
|
+
load("#{path}.rb") if File.exist?("#{path}.rb")
|
|
17
|
+
|
|
18
|
+
if File.directory? path
|
|
19
|
+
Dir[File.join(path, "**", "*.rb")].sort.each do |file|
|
|
20
|
+
load file
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
module FactoryBot
|
|
2
|
+
# @api private
|
|
3
|
+
module Internal
|
|
4
|
+
class << self
|
|
5
|
+
delegate :after,
|
|
6
|
+
:before,
|
|
7
|
+
:callbacks,
|
|
8
|
+
:constructor,
|
|
9
|
+
:factories,
|
|
10
|
+
:initialize_with,
|
|
11
|
+
:inline_sequences,
|
|
12
|
+
:sequences,
|
|
13
|
+
:skip_create,
|
|
14
|
+
:strategies,
|
|
15
|
+
:to_create,
|
|
16
|
+
:traits,
|
|
17
|
+
to: :configuration
|
|
18
|
+
|
|
19
|
+
def configuration
|
|
20
|
+
@configuration ||= Configuration.new
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def reset_configuration
|
|
24
|
+
@configuration = nil
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def register_inline_sequence(sequence)
|
|
28
|
+
inline_sequences.push(sequence)
|
|
29
|
+
sequence
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def rewind_inline_sequences
|
|
33
|
+
inline_sequences.each(&:rewind)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def register_trait(trait)
|
|
37
|
+
trait.names.each do |name|
|
|
38
|
+
traits.register(name, trait)
|
|
39
|
+
end
|
|
40
|
+
trait
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def trait_by_name(name, klass)
|
|
44
|
+
traits.find(name).tap { |t| t.klass = klass }
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def register_sequence(sequence)
|
|
48
|
+
sequence.names.each do |name|
|
|
49
|
+
sequences.register(name, sequence)
|
|
50
|
+
end
|
|
51
|
+
sequence
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def sequence_by_name(name)
|
|
55
|
+
sequences.find(name)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def rewind_sequences
|
|
59
|
+
sequences.each(&:rewind)
|
|
60
|
+
rewind_inline_sequences
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def rewind_sequence(*uri_parts)
|
|
64
|
+
fail_argument_count(0, "1+") if uri_parts.empty?
|
|
65
|
+
|
|
66
|
+
uri = build_uri(uri_parts)
|
|
67
|
+
sequence = Sequence.find_by_uri(uri) || fail_unregistered_sequence(uri)
|
|
68
|
+
|
|
69
|
+
sequence.rewind
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def set_sequence(*uri_parts, value)
|
|
73
|
+
uri = build_uri(uri_parts) || fail_argument_count(uri_parts.size, "2+")
|
|
74
|
+
sequence = Sequence.find(*uri) || fail_unregistered_sequence(uri)
|
|
75
|
+
|
|
76
|
+
sequence.set_value(value)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def register_factory(factory)
|
|
80
|
+
factory.names.each do |name|
|
|
81
|
+
factories.register(name, factory)
|
|
82
|
+
end
|
|
83
|
+
factory
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def factory_by_name(name)
|
|
87
|
+
factories.find(name)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def register_strategy(strategy_name, strategy_class)
|
|
91
|
+
strategies.register(strategy_name, strategy_class)
|
|
92
|
+
StrategySyntaxMethodRegistrar.new(strategy_name).define_strategy_methods
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def strategy_by_name(name)
|
|
96
|
+
strategies.find(name)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def register_default_strategies
|
|
100
|
+
register_strategy(:build, FactoryBot::Strategy::Build)
|
|
101
|
+
register_strategy(:create, FactoryBot::Strategy::Create)
|
|
102
|
+
register_strategy(:attributes_for, FactoryBot::Strategy::AttributesFor)
|
|
103
|
+
register_strategy(:build_stubbed, FactoryBot::Strategy::Stub)
|
|
104
|
+
register_strategy(:null, FactoryBot::Strategy::Null)
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
private
|
|
108
|
+
|
|
109
|
+
def build_uri(...)
|
|
110
|
+
FactoryBot::UriManager.build_uri(...)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def fail_argument_count(received, expected)
|
|
114
|
+
fail ArgumentError,
|
|
115
|
+
"wrong number of arguments (given #{received}, expected #{expected})"
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def fail_unregistered_sequence(uri)
|
|
119
|
+
fail KeyError,
|
|
120
|
+
"Sequence not registered: '#{uri}'."
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
end
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
module FactoryBot
|
|
2
|
+
class Linter
|
|
3
|
+
def initialize(factories, strategy: :create, traits: false, verbose: false)
|
|
4
|
+
@factories_to_lint = factories
|
|
5
|
+
@factory_strategy = strategy
|
|
6
|
+
@traits = traits
|
|
7
|
+
@verbose = verbose
|
|
8
|
+
@invalid_factories = calculate_invalid_factories
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def lint!
|
|
12
|
+
if invalid_factories.any?
|
|
13
|
+
raise InvalidFactoryError, error_message
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
private
|
|
18
|
+
|
|
19
|
+
attr_reader :factories_to_lint, :invalid_factories, :factory_strategy
|
|
20
|
+
|
|
21
|
+
def calculate_invalid_factories
|
|
22
|
+
factories_to_lint.each_with_object(Hash.new([])) do |factory, result|
|
|
23
|
+
errors = lint(factory)
|
|
24
|
+
result[factory] |= errors unless errors.empty?
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
class FactoryError
|
|
29
|
+
def initialize(wrapped_error, factory)
|
|
30
|
+
@wrapped_error = wrapped_error
|
|
31
|
+
@factory = factory
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def message
|
|
35
|
+
message = @wrapped_error.message
|
|
36
|
+
"* #{location} - #{message} (#{@wrapped_error.class.name})"
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def verbose_message
|
|
40
|
+
<<~MESSAGE
|
|
41
|
+
#{message}
|
|
42
|
+
#{@wrapped_error.backtrace.join("\n ")}
|
|
43
|
+
MESSAGE
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def location
|
|
47
|
+
@factory.name
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
class FactoryTraitError < FactoryError
|
|
52
|
+
def initialize(wrapped_error, factory, trait_name)
|
|
53
|
+
super(wrapped_error, factory)
|
|
54
|
+
@trait_name = trait_name
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def location
|
|
58
|
+
"#{@factory.name}+#{@trait_name}"
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def lint(factory)
|
|
63
|
+
if @traits
|
|
64
|
+
lint_factory(factory) + lint_traits(factory)
|
|
65
|
+
else
|
|
66
|
+
lint_factory(factory)
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def lint_factory(factory)
|
|
71
|
+
result = []
|
|
72
|
+
begin
|
|
73
|
+
in_transaction { FactoryBot.public_send(factory_strategy, factory.name) }
|
|
74
|
+
rescue => e
|
|
75
|
+
result |= [FactoryError.new(e, factory)]
|
|
76
|
+
end
|
|
77
|
+
result
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def lint_traits(factory)
|
|
81
|
+
result = []
|
|
82
|
+
factory.definition.defined_traits.map(&:name).each do |trait_name|
|
|
83
|
+
in_transaction { FactoryBot.public_send(factory_strategy, factory.name, trait_name) }
|
|
84
|
+
rescue => e
|
|
85
|
+
result |= [FactoryTraitError.new(e, factory, trait_name)]
|
|
86
|
+
end
|
|
87
|
+
result
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def error_message
|
|
91
|
+
lines = invalid_factories.map { |_factory, exceptions|
|
|
92
|
+
exceptions.map(&error_message_type)
|
|
93
|
+
}.flatten
|
|
94
|
+
|
|
95
|
+
<<~ERROR_MESSAGE.strip
|
|
96
|
+
The following factories are invalid:
|
|
97
|
+
|
|
98
|
+
#{lines.join("\n")}
|
|
99
|
+
ERROR_MESSAGE
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def error_message_type
|
|
103
|
+
if @verbose
|
|
104
|
+
:verbose_message
|
|
105
|
+
else
|
|
106
|
+
:message
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def in_transaction
|
|
111
|
+
if defined?(ActiveRecord::Base)
|
|
112
|
+
ActiveRecord::Base.transaction(joinable: false) do
|
|
113
|
+
yield
|
|
114
|
+
raise ActiveRecord::Rollback
|
|
115
|
+
end
|
|
116
|
+
else
|
|
117
|
+
yield
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
module FactoryBot
|
|
2
|
+
# @api private
|
|
3
|
+
class NullFactory
|
|
4
|
+
attr_reader :definition
|
|
5
|
+
|
|
6
|
+
def initialize
|
|
7
|
+
@definition = Definition.new(:null_factory)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
delegate :defined_traits, :callbacks, :attributes, :constructor,
|
|
11
|
+
:to_create, to: :definition
|
|
12
|
+
|
|
13
|
+
def compile
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def class_name
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def evaluator_class
|
|
20
|
+
FactoryBot::Evaluator
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def hierarchy_class
|
|
24
|
+
FactoryBot::DefinitionHierarchy
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
module FactoryBot
|
|
2
|
+
# @api private
|
|
3
|
+
class NullObject < ::BasicObject
|
|
4
|
+
def initialize(methods_to_respond_to)
|
|
5
|
+
@methods_to_respond_to = methods_to_respond_to.map(&:to_s)
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def method_missing(name, *args, &block) # rubocop:disable Style/MissingRespondToMissing
|
|
9
|
+
if respond_to?(name)
|
|
10
|
+
nil
|
|
11
|
+
else
|
|
12
|
+
super
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def respond_to?(method)
|
|
17
|
+
@methods_to_respond_to.include? method.to_s
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|