factory_bot 4.10.0 → 6.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (80) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +1 -0
  3. data/CONTRIBUTING.md +52 -13
  4. data/GETTING_STARTED.md +613 -182
  5. data/LICENSE +1 -1
  6. data/NEWS.md +358 -0
  7. data/README.md +30 -26
  8. data/lib/factory_bot.rb +71 -140
  9. data/lib/factory_bot/aliases.rb +2 -2
  10. data/lib/factory_bot/attribute.rb +4 -39
  11. data/lib/factory_bot/attribute/association.rb +2 -2
  12. data/lib/factory_bot/attribute/dynamic.rb +2 -1
  13. data/lib/factory_bot/attribute_assigner.rb +24 -10
  14. data/lib/factory_bot/attribute_list.rb +3 -2
  15. data/lib/factory_bot/callback.rb +3 -10
  16. data/lib/factory_bot/configuration.rb +15 -19
  17. data/lib/factory_bot/declaration.rb +5 -5
  18. data/lib/factory_bot/declaration/association.rb +14 -1
  19. data/lib/factory_bot/declaration/dynamic.rb +3 -1
  20. data/lib/factory_bot/declaration/implicit.rb +7 -2
  21. data/lib/factory_bot/declaration_list.rb +3 -3
  22. data/lib/factory_bot/decorator.rb +5 -5
  23. data/lib/factory_bot/decorator/attribute_hash.rb +1 -1
  24. data/lib/factory_bot/decorator/invocation_tracker.rb +1 -1
  25. data/lib/factory_bot/definition.rb +49 -20
  26. data/lib/factory_bot/definition_hierarchy.rb +1 -11
  27. data/lib/factory_bot/definition_proxy.rb +125 -43
  28. data/lib/factory_bot/enum.rb +27 -0
  29. data/lib/factory_bot/errors.rb +7 -4
  30. data/lib/factory_bot/evaluation.rb +1 -1
  31. data/lib/factory_bot/evaluator.rb +9 -11
  32. data/lib/factory_bot/evaluator_class_definer.rb +1 -1
  33. data/lib/factory_bot/factory.rb +12 -12
  34. data/lib/factory_bot/factory_runner.rb +4 -4
  35. data/lib/factory_bot/find_definitions.rb +2 -2
  36. data/lib/factory_bot/internal.rb +91 -0
  37. data/lib/factory_bot/linter.rb +41 -28
  38. data/lib/factory_bot/null_factory.rb +13 -4
  39. data/lib/factory_bot/null_object.rb +2 -6
  40. data/lib/factory_bot/registry.rb +17 -8
  41. data/lib/factory_bot/reload.rb +2 -3
  42. data/lib/factory_bot/sequence.rb +5 -6
  43. data/lib/factory_bot/strategy/stub.rb +37 -37
  44. data/lib/factory_bot/strategy_calculator.rb +1 -1
  45. data/lib/factory_bot/strategy_syntax_method_registrar.rb +13 -2
  46. data/lib/factory_bot/syntax.rb +2 -2
  47. data/lib/factory_bot/syntax/default.rb +12 -24
  48. data/lib/factory_bot/syntax/methods.rb +32 -9
  49. data/lib/factory_bot/trait.rb +7 -4
  50. data/lib/factory_bot/version.rb +1 -1
  51. metadata +50 -65
  52. data/.autotest +0 -9
  53. data/.gitignore +0 -10
  54. data/.rspec +0 -3
  55. data/.simplecov +0 -4
  56. data/.travis.yml +0 -58
  57. data/Appraisals +0 -23
  58. data/Gemfile +0 -8
  59. data/Gemfile.lock +0 -103
  60. data/NEWS +0 -298
  61. data/Rakefile +0 -36
  62. data/cucumber.yml +0 -1
  63. data/factory_bot.gemspec +0 -36
  64. data/factory_girl.gemspec +0 -40
  65. data/gemfiles/3.2.gemfile +0 -10
  66. data/gemfiles/3.2.gemfile.lock +0 -107
  67. data/gemfiles/4.0.gemfile +0 -10
  68. data/gemfiles/4.0.gemfile.lock +0 -107
  69. data/gemfiles/4.1.gemfile +0 -10
  70. data/gemfiles/4.1.gemfile.lock +0 -106
  71. data/gemfiles/4.2.gemfile +0 -10
  72. data/gemfiles/4.2.gemfile.lock +0 -106
  73. data/gemfiles/5.0.gemfile +0 -10
  74. data/gemfiles/5.0.gemfile.lock +0 -104
  75. data/gemfiles/5.1.gemfile +0 -10
  76. data/gemfiles/5.1.gemfile.lock +0 -104
  77. data/lib/factory_bot/attribute/static.rb +0 -16
  78. data/lib/factory_bot/declaration/static.rb +0 -26
  79. data/lib/factory_bot/decorator/class_key_hash.rb +0 -28
  80. data/lib/factory_girl.rb +0 -5
@@ -1,21 +1,25 @@
1
1
  module FactoryBot
2
2
  # @api private
3
3
  class Configuration
4
- attr_reader :factories, :sequences, :traits, :strategies, :callback_names
5
-
6
- attr_accessor :allow_class_lookup, :use_parent_strategy
4
+ attr_reader(
5
+ :callback_names,
6
+ :factories,
7
+ :inline_sequences,
8
+ :sequences,
9
+ :strategies,
10
+ :traits
11
+ )
7
12
 
8
13
  def initialize
9
- @factories = Decorator::DisallowsDuplicatesRegistry.new(Registry.new('Factory'))
10
- @sequences = Decorator::DisallowsDuplicatesRegistry.new(Registry.new('Sequence'))
11
- @traits = Decorator::DisallowsDuplicatesRegistry.new(Registry.new('Trait'))
12
- @strategies = Registry.new('Strategy')
14
+ @factories = Decorator::DisallowsDuplicatesRegistry.new(Registry.new("Factory"))
15
+ @sequences = Decorator::DisallowsDuplicatesRegistry.new(Registry.new("Sequence"))
16
+ @traits = Decorator::DisallowsDuplicatesRegistry.new(Registry.new("Trait"))
17
+ @strategies = Registry.new("Strategy")
13
18
  @callback_names = Set.new
14
- @definition = Definition.new
15
-
16
- @allow_class_lookup = true
19
+ @definition = Definition.new(:configuration)
20
+ @inline_sequences = []
17
21
 
18
- to_create { |instance| instance.save! }
22
+ to_create(&:save!)
19
23
  initialize_with { new }
20
24
  end
21
25
 
@@ -25,13 +29,5 @@ module FactoryBot
25
29
  def initialize_with(&block)
26
30
  @definition.define_constructor(&block)
27
31
  end
28
-
29
- def duplicate_attribute_assignment_from_initialize_with
30
- false
31
- end
32
-
33
- def duplicate_attribute_assignment_from_initialize_with=(value)
34
- ActiveSupport::Deprecation.warn 'Assignment of duplicate_attribute_assignment_from_initialize_with is unnecessary as this is now default behavior in FactoryBot 4.0; this line can be removed', caller
35
- end
36
32
  end
37
33
  end
@@ -1,7 +1,6 @@
1
- require 'factory_bot/declaration/static'
2
- require 'factory_bot/declaration/dynamic'
3
- require 'factory_bot/declaration/association'
4
- require 'factory_bot/declaration/implicit'
1
+ require "factory_bot/declaration/dynamic"
2
+ require "factory_bot/declaration/association"
3
+ require "factory_bot/declaration/implicit"
5
4
 
6
5
  module FactoryBot
7
6
  # @api private
@@ -9,7 +8,7 @@ module FactoryBot
9
8
  attr_reader :name
10
9
 
11
10
  def initialize(name, ignored = false)
12
- @name = name
11
+ @name = name
13
12
  @ignored = ignored
14
13
  end
15
14
 
@@ -18,6 +17,7 @@ module FactoryBot
18
17
  end
19
18
 
20
19
  protected
20
+
21
21
  attr_reader :ignored
22
22
  end
23
23
  end
@@ -10,19 +10,32 @@ module FactoryBot
10
10
  end
11
11
 
12
12
  def ==(other)
13
- name == other.name &&
13
+ self.class == other.class &&
14
+ name == other.name &&
14
15
  options == other.options
15
16
  end
16
17
 
17
18
  protected
19
+
18
20
  attr_reader :options
19
21
 
20
22
  private
21
23
 
22
24
  def build
25
+ ensure_factory_is_not_a_declaration!
26
+
23
27
  factory_name = @overrides[:factory] || name
24
28
  [Attribute::Association.new(name, factory_name, [@traits, @overrides.except(:factory)].flatten)]
25
29
  end
30
+
31
+ def ensure_factory_is_not_a_declaration!
32
+ if @overrides[:factory].is_a?(Declaration)
33
+ raise ArgumentError.new(<<~MSG)
34
+ Association '#{name}' received an invalid factory argument.
35
+ Did you mean? 'factory: :#{@overrides[:factory].name}'
36
+ MSG
37
+ end
38
+ end
26
39
  end
27
40
  end
28
41
  end
@@ -8,12 +8,14 @@ module FactoryBot
8
8
  end
9
9
 
10
10
  def ==(other)
11
- name == other.name &&
11
+ self.class == other.class &&
12
+ name == other.name &&
12
13
  ignored == other.ignored &&
13
14
  block == other.block
14
15
  end
15
16
 
16
17
  protected
18
+
17
19
  attr_reader :block
18
20
 
19
21
  private
@@ -8,12 +8,14 @@ module FactoryBot
8
8
  end
9
9
 
10
10
  def ==(other)
11
- name == other.name &&
11
+ self.class == other.class &&
12
+ name == other.name &&
12
13
  factory == other.factory &&
13
14
  ignored == other.ignored
14
15
  end
15
16
 
16
17
  protected
18
+
17
19
  attr_reader :factory
18
20
 
19
21
  private
@@ -21,8 +23,11 @@ module FactoryBot
21
23
  def build
22
24
  if FactoryBot.factories.registered?(name)
23
25
  [Attribute::Association.new(name, name, {})]
24
- elsif FactoryBot.sequences.registered?(name)
26
+ elsif FactoryBot::Internal.sequences.registered?(name)
25
27
  [Attribute::Sequence.new(name, name, @ignored)]
28
+ elsif @factory.name.to_s == name.to_s
29
+ message = "Self-referencing trait '#{@name}'"
30
+ raise TraitDefinitionError, message
26
31
  else
27
32
  @factory.inherit_traits([name])
28
33
  []
@@ -5,8 +5,8 @@ module FactoryBot
5
5
 
6
6
  def initialize(name = nil)
7
7
  @declarations = []
8
- @name = name
9
- @overridable = false
8
+ @name = name
9
+ @overridable = false
10
10
  end
11
11
 
12
12
  def declare_attribute(declaration)
@@ -39,7 +39,7 @@ module FactoryBot
39
39
  end
40
40
 
41
41
  def to_attributes
42
- @declarations.inject([]) { |result, declaration| result += declaration.to_attributes }
42
+ @declarations.reduce([]) { |result, declaration| result + declaration.to_attributes }
43
43
  end
44
44
 
45
45
  def overridable?
@@ -6,16 +6,16 @@ module FactoryBot
6
6
  @component = component
7
7
  end
8
8
 
9
- def method_missing(name, *args, &block)
9
+ def method_missing(name, *args, &block) # rubocop:disable Style/MethodMissingSuper
10
10
  @component.send(name, *args, &block)
11
11
  end
12
12
 
13
- def send(symbol, *args, &block)
14
- __send__(symbol, *args, &block)
13
+ def respond_to_missing?(name, include_private = false)
14
+ @component.respond_to?(name, true) || super
15
15
  end
16
16
 
17
- def self.const_missing(name)
18
- ::Object.const_get(name)
17
+ def send(symbol, *args, &block)
18
+ __send__(symbol, *args, &block)
19
19
  end
20
20
  end
21
21
  end
@@ -8,7 +8,7 @@ module FactoryBot
8
8
 
9
9
  def attributes
10
10
  @attributes.each_with_object({}) do |attribute_name, result|
11
- result[attribute_name] = send(attribute_name)
11
+ result[attribute_name] = @component.send(attribute_name)
12
12
  end
13
13
  end
14
14
  end
@@ -6,7 +6,7 @@ module FactoryBot
6
6
  @invoked_methods = []
7
7
  end
8
8
 
9
- def method_missing(name, *args, &block)
9
+ def method_missing(name, *args, &block) # rubocop:disable Style/MissingRespondToMissing
10
10
  @invoked_methods << name
11
11
  super
12
12
  end
@@ -1,18 +1,20 @@
1
1
  module FactoryBot
2
2
  # @api private
3
3
  class Definition
4
- attr_reader :defined_traits, :declarations
5
-
6
- def initialize(name = nil, base_traits = [])
7
- @declarations = DeclarationList.new(name)
8
- @callbacks = []
9
- @defined_traits = Set.new
10
- @to_create = nil
11
- @base_traits = base_traits
4
+ attr_reader :defined_traits, :declarations, :name, :registered_enums
5
+
6
+ def initialize(name, base_traits = [])
7
+ @name = name
8
+ @declarations = DeclarationList.new(name)
9
+ @callbacks = []
10
+ @defined_traits = Set.new
11
+ @registered_enums = []
12
+ @to_create = nil
13
+ @base_traits = base_traits
12
14
  @additional_traits = []
13
- @constructor = nil
14
- @attributes = nil
15
- @compiled = false
15
+ @constructor = nil
16
+ @attributes = nil
17
+ @compiled = false
16
18
  end
17
19
 
18
20
  delegate :declare_attribute, to: :declarations
@@ -42,13 +44,15 @@ module FactoryBot
42
44
  aggregate_from_traits_and_self(:callbacks) { @callbacks }
43
45
  end
44
46
 
45
- def compile
47
+ def compile(klass = nil)
46
48
  unless @compiled
49
+ expand_enum_traits(klass) unless klass.nil?
50
+
47
51
  declarations.attributes
48
52
 
49
53
  defined_traits.each do |defined_trait|
50
- base_traits.each { |bt| bt.define_trait defined_trait }
51
- additional_traits.each { |bt| bt.define_trait defined_trait }
54
+ base_traits.each { |bt| bt.define_trait defined_trait }
55
+ additional_traits.each { |at| at.define_trait defined_trait }
52
56
  end
53
57
 
54
58
  @compiled = true
@@ -73,13 +77,17 @@ module FactoryBot
73
77
  end
74
78
 
75
79
  def skip_create
76
- @to_create = ->(instance) { }
80
+ @to_create = ->(instance) {}
77
81
  end
78
82
 
79
83
  def define_trait(trait)
80
84
  @defined_traits.add(trait)
81
85
  end
82
86
 
87
+ def register_enum(enum)
88
+ @registered_enums << enum
89
+ end
90
+
83
91
  def define_constructor(&block)
84
92
  @constructor = block
85
93
  end
@@ -94,7 +102,6 @@ module FactoryBot
94
102
 
95
103
  def callback(*names, &block)
96
104
  names.each do |name|
97
- FactoryBot.register_callback(name)
98
105
  add_callback(Callback.new(name, block))
99
106
  end
100
107
  end
@@ -110,17 +117,19 @@ module FactoryBot
110
117
  end
111
118
 
112
119
  def trait_by_name(name)
113
- trait_for(name) || FactoryBot.trait_by_name(name)
120
+ trait_for(name) || Internal.trait_by_name(name)
114
121
  end
115
122
 
116
123
  def trait_for(name)
117
- defined_traits.detect { |trait| trait.name == name }
124
+ @defined_traits_by_name ||= defined_traits.each_with_object({}) { |t, memo| memo[t.name] ||= t }
125
+ @defined_traits_by_name[name.to_s]
118
126
  end
119
127
 
120
128
  def initialize_copy(source)
121
129
  super
122
130
  @attributes = nil
123
- @compiled = false
131
+ @compiled = false
132
+ @defined_traits_by_name = nil
124
133
  end
125
134
 
126
135
  def aggregate_from_traits_and_self(method_name, &block)
@@ -129,8 +138,28 @@ module FactoryBot
129
138
  [
130
139
  base_traits.map(&method_name),
131
140
  instance_exec(&block),
132
- additional_traits.map(&method_name),
141
+ additional_traits.map(&method_name)
133
142
  ].flatten.compact
134
143
  end
144
+
145
+ def expand_enum_traits(klass)
146
+ if automatically_register_defined_enums?(klass)
147
+ automatically_register_defined_enums(klass)
148
+ end
149
+
150
+ registered_enums.each do |enum|
151
+ traits = enum.build_traits(klass)
152
+ traits.each { |trait| define_trait(trait) }
153
+ end
154
+ end
155
+
156
+ def automatically_register_defined_enums(klass)
157
+ klass.defined_enums.each_key { |name| register_enum(Enum.new(name)) }
158
+ end
159
+
160
+ def automatically_register_defined_enums?(klass)
161
+ FactoryBot.automatically_define_enum_traits &&
162
+ klass.respond_to?(:defined_enums)
163
+ end
135
164
  end
136
165
  end
@@ -1,16 +1,6 @@
1
1
  module FactoryBot
2
2
  class DefinitionHierarchy
3
- def callbacks
4
- FactoryBot.callbacks
5
- end
6
-
7
- def constructor
8
- FactoryBot.constructor
9
- end
10
-
11
- def to_create
12
- FactoryBot.to_create
13
- end
3
+ delegate :callbacks, :constructor, :to_create, to: Internal
14
4
 
15
5
  def self.build_from_definition(definition)
16
6
  build_to_create(&definition.to_create)
@@ -1,6 +1,19 @@
1
1
  module FactoryBot
2
2
  class DefinitionProxy
3
- UNPROXIED_METHODS = %w(__send__ __id__ nil? send object_id extend instance_eval initialize block_given? raise caller method)
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
4
17
 
5
18
  (instance_methods + private_instance_methods).each do |method|
6
19
  undef_method(method) unless UNPROXIED_METHODS.include?(method.to_s)
@@ -11,8 +24,8 @@ module FactoryBot
11
24
  attr_reader :child_factories
12
25
 
13
26
  def initialize(definition, ignore = false)
14
- @definition = definition
15
- @ignore = ignore
27
+ @definition = definition
28
+ @ignore = ignore
16
29
  @child_factories = []
17
30
  end
18
31
 
@@ -21,42 +34,21 @@ module FactoryBot
21
34
  raise FactoryBot::MethodDefinitionError, message
22
35
  end
23
36
 
24
- # Adds an attribute that should be assigned on generated instances for this
25
- # factory.
26
- #
27
- # This method should be called with either a value or block, but not both. If
28
- # called with a block, the attribute will be generated "lazily," whenever an
29
- # instance is generated. Lazy attribute blocks will not be called if that
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
30
41
  # attribute is overridden for a specific instance.
31
42
  #
32
- # When defining lazy attributes, an instance of FactoryBot::Strategy will
33
- # be yielded, allowing associations to be built using the correct build
34
- # strategy.
35
- #
36
43
  # Arguments:
37
44
  # * name: +Symbol+ or +String+
38
45
  # The name of this attribute. This will be assigned using "name=" for
39
46
  # generated instances.
40
- # * value: +Object+
41
- # If no block is given, this value will be used for this attribute.
42
- def add_attribute(name, value = nil, &block)
43
- raise AttributeDefinitionError, 'Both value and block given' if value && block_given?
44
-
45
- declaration = if block_given?
46
- Declaration::Dynamic.new(name, @ignore, block)
47
- else
48
- Declaration::Static.new(name, value, @ignore)
49
- end
50
-
47
+ def add_attribute(name, &block)
48
+ declaration = Declaration::Dynamic.new(name, @ignore, block)
51
49
  @definition.declare_attribute(declaration)
52
50
  end
53
51
 
54
- def ignore(&block)
55
- ActiveSupport::Deprecation.warn "`#ignore` is deprecated and will be "\
56
- "removed in 5.0. Please use `#transient` instead."
57
- transient(&block)
58
- end
59
-
60
52
  def transient(&block)
61
53
  proxy = DefinitionProxy.new(@definition, true)
62
54
  proxy.instance_eval(&block)
@@ -66,40 +58,48 @@ module FactoryBot
66
58
  # attribute, so that:
67
59
  #
68
60
  # factory :user do
69
- # name 'Billy Idol'
61
+ # name { 'Billy Idol' }
70
62
  # end
71
63
  #
72
64
  # and:
73
65
  #
74
66
  # factory :user do
75
- # add_attribute :name, 'Billy Idol'
67
+ # add_attribute(:name) { 'Billy Idol' }
76
68
  # end
77
69
  #
78
70
  # are equivalent.
79
71
  #
80
- # If no argument or block is given, factory_bot will look for a sequence
81
- # or association with the same name. This means that:
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:
82
76
  #
83
- # factory :user do
84
- # email { create(:email) }
77
+ # factory :user, traits: [:admin] do
78
+ # email { generate(:email) }
85
79
  # association :account
86
80
  # end
87
81
  #
88
82
  # and:
89
83
  #
90
84
  # factory :user do
85
+ # admin
91
86
  # email
92
87
  # account
93
88
  # end
94
89
  #
95
90
  # are equivalent.
96
- def method_missing(name, *args, &block)
97
- if args.empty? && block.nil?
98
- @definition.declare_attribute(Declaration::Implicit.new(name, @definition, @ignore))
99
- elsif args.first.respond_to?(:has_key?) && args.first.has_key?(:factory)
100
- association(name, *args)
91
+ def method_missing(name, *args, &block) # rubocop:disable Style/MissingRespondToMissing, Style/MethodMissingSuper
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)
101
98
  else
102
- add_attribute(name, *args, &block)
99
+ raise NoMethodError.new(<<~MSG)
100
+ undefined method '#{name}' in '#{@definition.name}' factory
101
+ Did you mean? '#{name} { #{association_options.inspect} }'
102
+ MSG
103
103
  end
104
104
  end
105
105
 
@@ -121,6 +121,7 @@ module FactoryBot
121
121
  # Except that no globally available sequence will be defined.
122
122
  def sequence(name, *args, &block)
123
123
  sequence = Sequence.new(name, *args, &block)
124
+ FactoryBot::Internal.register_inline_sequence(sequence)
124
125
  add_attribute(name) { increment_sequence(sequence) }
125
126
  end
126
127
 
@@ -148,7 +149,15 @@ module FactoryBot
148
149
  # name of the factory. For example, a "user" association will by
149
150
  # default use the "user" factory.
150
151
  def association(name, *options)
151
- @definition.declare_attribute(Declaration::Association.new(name, *options))
152
+ if block_given?
153
+ raise AssociationDefinitionError.new(
154
+ "Unexpected block passed to '#{name}' association "\
155
+ "in '#{@definition.name}' factory"
156
+ )
157
+ else
158
+ declaration = Declaration::Association.new(name, *options)
159
+ @definition.declare_attribute(declaration)
160
+ end
152
161
  end
153
162
 
154
163
  def to_create(&block)
@@ -167,8 +176,81 @@ module FactoryBot
167
176
  @definition.define_trait(Trait.new(name, &block))
168
177
  end
169
178
 
179
+ # Creates traits for enumerable values.
180
+ #
181
+ # Example:
182
+ # factory :task do
183
+ # traits_for_enum :status, [:started, :finished]
184
+ # end
185
+ #
186
+ # Equivalent to:
187
+ # factory :task do
188
+ # trait :started do
189
+ # status { :started }
190
+ # end
191
+ #
192
+ # trait :finished do
193
+ # status { :finished }
194
+ # end
195
+ # end
196
+ #
197
+ # Example:
198
+ # factory :task do
199
+ # traits_for_enum :status, {started: 1, finished: 2}
200
+ # end
201
+ #
202
+ # Example:
203
+ # class Task
204
+ # def statuses
205
+ # {started: 1, finished: 2}
206
+ # end
207
+ # end
208
+ #
209
+ # factory :task do
210
+ # traits_for_enum :status
211
+ # end
212
+ #
213
+ # Both equivalent to:
214
+ # factory :task do
215
+ # trait :started do
216
+ # status { 1 }
217
+ # end
218
+ #
219
+ # trait :finished do
220
+ # status { 2 }
221
+ # end
222
+ # end
223
+ #
224
+ #
225
+ # Arguments:
226
+ # attribute_name: +Symbol+ or +String+
227
+ # the name of the attribute these traits will set the value of
228
+ # values: +Array+, +Hash+, or other +Enumerable+
229
+ # An array of trait names, or a mapping of trait names to values for
230
+ # those traits. When this argument is not provided, factory_bot will
231
+ # attempt to get the values by calling the pluralized `attribute_name`
232
+ # class method.
233
+ def traits_for_enum(attribute_name, values = nil)
234
+ @definition.register_enum(Enum.new(attribute_name, values))
235
+ end
236
+
170
237
  def initialize_with(&block)
171
238
  @definition.define_constructor(&block)
172
239
  end
240
+
241
+ private
242
+
243
+ def __declare_attribute__(name, block)
244
+ if block.nil?
245
+ declaration = Declaration::Implicit.new(name, @definition, @ignore)
246
+ @definition.declare_attribute(declaration)
247
+ else
248
+ add_attribute(name, &block)
249
+ end
250
+ end
251
+
252
+ def __valid_association_options?(options)
253
+ options.respond_to?(:has_key?) && options.has_key?(:factory)
254
+ end
173
255
  end
174
256
  end