factory_bot 1.0.0.alpha

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.
Files changed (86) hide show
  1. checksums.yaml +7 -0
  2. data/.autotest +9 -0
  3. data/.gitignore +9 -0
  4. data/.rspec +2 -0
  5. data/.simplecov +4 -0
  6. data/.travis.yml +41 -0
  7. data/.yardopts +5 -0
  8. data/Appraisals +19 -0
  9. data/CONTRIBUTING.md +60 -0
  10. data/GETTING_STARTED.md +1387 -0
  11. data/Gemfile +8 -0
  12. data/Gemfile.lock +123 -0
  13. data/LICENSE +19 -0
  14. data/NAME.md +11 -0
  15. data/NEWS +285 -0
  16. data/README.md +102 -0
  17. data/Rakefile +36 -0
  18. data/cucumber.yml +1 -0
  19. data/factory_bot.gemspec +38 -0
  20. data/factory_girl.gemspec +41 -0
  21. data/gemfiles/3.2.gemfile +10 -0
  22. data/gemfiles/3.2.gemfile.lock +112 -0
  23. data/gemfiles/4.0.gemfile +10 -0
  24. data/gemfiles/4.0.gemfile.lock +112 -0
  25. data/gemfiles/4.1.gemfile +10 -0
  26. data/gemfiles/4.1.gemfile.lock +111 -0
  27. data/gemfiles/4.2.gemfile +10 -0
  28. data/gemfiles/4.2.gemfile.lock +111 -0
  29. data/gemfiles/5.0.gemfile +10 -0
  30. data/gemfiles/5.0.gemfile.lock +110 -0
  31. data/lib/factory_bot.rb +154 -0
  32. data/lib/factory_bot/aliases.rb +18 -0
  33. data/lib/factory_bot/attribute.rb +62 -0
  34. data/lib/factory_bot/attribute/association.rb +27 -0
  35. data/lib/factory_bot/attribute/dynamic.rb +24 -0
  36. data/lib/factory_bot/attribute/sequence.rb +16 -0
  37. data/lib/factory_bot/attribute/static.rb +16 -0
  38. data/lib/factory_bot/attribute_assigner.rb +97 -0
  39. data/lib/factory_bot/attribute_list.rb +67 -0
  40. data/lib/factory_bot/callback.rb +40 -0
  41. data/lib/factory_bot/callbacks_observer.rb +21 -0
  42. data/lib/factory_bot/configuration.rb +37 -0
  43. data/lib/factory_bot/declaration.rb +23 -0
  44. data/lib/factory_bot/declaration/association.rb +28 -0
  45. data/lib/factory_bot/declaration/dynamic.rb +26 -0
  46. data/lib/factory_bot/declaration/implicit.rb +33 -0
  47. data/lib/factory_bot/declaration/static.rb +26 -0
  48. data/lib/factory_bot/declaration_list.rb +49 -0
  49. data/lib/factory_bot/decorator.rb +21 -0
  50. data/lib/factory_bot/decorator/attribute_hash.rb +16 -0
  51. data/lib/factory_bot/decorator/class_key_hash.rb +28 -0
  52. data/lib/factory_bot/decorator/disallows_duplicates_registry.rb +13 -0
  53. data/lib/factory_bot/decorator/invocation_tracker.rb +19 -0
  54. data/lib/factory_bot/decorator/new_constructor.rb +12 -0
  55. data/lib/factory_bot/definition.rb +136 -0
  56. data/lib/factory_bot/definition_hierarchy.rb +48 -0
  57. data/lib/factory_bot/definition_proxy.rb +174 -0
  58. data/lib/factory_bot/errors.rb +25 -0
  59. data/lib/factory_bot/evaluation.rb +23 -0
  60. data/lib/factory_bot/evaluator.rb +82 -0
  61. data/lib/factory_bot/evaluator_class_definer.rb +20 -0
  62. data/lib/factory_bot/factory.rb +162 -0
  63. data/lib/factory_bot/factory_runner.rb +33 -0
  64. data/lib/factory_bot/find_definitions.rb +25 -0
  65. data/lib/factory_bot/linter.rb +97 -0
  66. data/lib/factory_bot/null_factory.rb +18 -0
  67. data/lib/factory_bot/null_object.rb +24 -0
  68. data/lib/factory_bot/registry.rb +38 -0
  69. data/lib/factory_bot/reload.rb +8 -0
  70. data/lib/factory_bot/sequence.rb +62 -0
  71. data/lib/factory_bot/strategy/attributes_for.rb +13 -0
  72. data/lib/factory_bot/strategy/build.rb +15 -0
  73. data/lib/factory_bot/strategy/create.rb +18 -0
  74. data/lib/factory_bot/strategy/null.rb +11 -0
  75. data/lib/factory_bot/strategy/stub.rb +108 -0
  76. data/lib/factory_bot/strategy_calculator.rb +26 -0
  77. data/lib/factory_bot/strategy_syntax_method_registrar.rb +54 -0
  78. data/lib/factory_bot/syntax.rb +7 -0
  79. data/lib/factory_bot/syntax/default.rb +76 -0
  80. data/lib/factory_bot/syntax/methods.rb +111 -0
  81. data/lib/factory_bot/syntax_runner.rb +6 -0
  82. data/lib/factory_bot/trait.rb +30 -0
  83. data/lib/factory_bot/version.rb +3 -0
  84. data/lib/factory_girl.rb +5 -0
  85. data/lib/factory_girl/version.rb +1 -0
  86. metadata +302 -0
@@ -0,0 +1,28 @@
1
+ module FactoryBot
2
+ class Declaration
3
+ # @api private
4
+ class Association < Declaration
5
+ def initialize(name, *options)
6
+ super(name, false)
7
+ @options = options.dup
8
+ @overrides = options.extract_options!
9
+ @traits = options
10
+ end
11
+
12
+ def ==(other)
13
+ name == other.name &&
14
+ options == other.options
15
+ end
16
+
17
+ protected
18
+ attr_reader :options
19
+
20
+ private
21
+
22
+ def build
23
+ factory_name = @overrides[:factory] || name
24
+ [Attribute::Association.new(name, factory_name, [@traits, @overrides.except(:factory)].flatten)]
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,26 @@
1
+ module FactoryBot
2
+ class Declaration
3
+ # @api private
4
+ class Dynamic < Declaration
5
+ def initialize(name, ignored = false, block = nil)
6
+ super(name, ignored)
7
+ @block = block
8
+ end
9
+
10
+ def ==(other)
11
+ name == other.name &&
12
+ ignored == other.ignored &&
13
+ block == other.block
14
+ end
15
+
16
+ protected
17
+ attr_reader :block
18
+
19
+ private
20
+
21
+ def build
22
+ [Attribute::Dynamic.new(name, @ignored, @block)]
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,33 @@
1
+ module FactoryBot
2
+ class Declaration
3
+ # @api private
4
+ class Implicit < Declaration
5
+ def initialize(name, factory = nil, ignored = false)
6
+ super(name, ignored)
7
+ @factory = factory
8
+ end
9
+
10
+ def ==(other)
11
+ name == other.name &&
12
+ factory == other.factory &&
13
+ ignored == other.ignored
14
+ end
15
+
16
+ protected
17
+ attr_reader :factory
18
+
19
+ private
20
+
21
+ def build
22
+ if FactoryBot.factories.registered?(name)
23
+ [Attribute::Association.new(name, name, {})]
24
+ elsif FactoryBot.sequences.registered?(name)
25
+ [Attribute::Sequence.new(name, name, @ignored)]
26
+ else
27
+ @factory.inherit_traits([name])
28
+ []
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,26 @@
1
+ module FactoryBot
2
+ class Declaration
3
+ # @api private
4
+ class Static < Declaration
5
+ def initialize(name, value, ignored = false)
6
+ super(name, ignored)
7
+ @value = value
8
+ end
9
+
10
+ def ==(other)
11
+ name == other.name &&
12
+ value == other.value &&
13
+ ignored == other.ignored
14
+ end
15
+
16
+ protected
17
+ attr_reader :value
18
+
19
+ private
20
+
21
+ def build
22
+ [Attribute::Static.new(name, @value, @ignored)]
23
+ end
24
+ end
25
+ end
26
+ 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.inject([]) { |result, declaration| result += declaration.to_attributes }
43
+ end
44
+
45
+ def overridable?
46
+ @overridable
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,21 @@
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(name, *args, &block)
10
+ @component.send(name, *args, &block)
11
+ end
12
+
13
+ def send(symbol, *args, &block)
14
+ __send__(symbol, *args, &block)
15
+ end
16
+
17
+ def self.const_missing(name)
18
+ ::Object.const_get(name)
19
+ end
20
+ end
21
+ 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] = send(attribute_name)
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,28 @@
1
+ module FactoryBot
2
+ class Decorator
3
+ class ClassKeyHash < Decorator
4
+ def [](key)
5
+ @component[symbolized_key key]
6
+ end
7
+
8
+ def []=(key, value)
9
+ @component[symbolized_key key] = value
10
+ end
11
+
12
+ def key?(key)
13
+ @component.key? symbolized_key(key)
14
+ end
15
+
16
+ private
17
+
18
+ def symbolized_key(key)
19
+ if key.respond_to?(:to_sym)
20
+ key.to_sym
21
+ elsif FactoryBot.allow_class_lookup
22
+ ActiveSupport::Deprecation.warn "Looking up factories by class is deprecated and will be removed in 5.0. Use symbols instead and set FactoryBot.allow_class_lookup = false", caller
23
+ key.to_s.underscore.to_sym
24
+ end
25
+ end
26
+ end
27
+ end
28
+ 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,19 @@
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)
10
+ @invoked_methods << name
11
+ super
12
+ end
13
+
14
+ def __invoked_methods__
15
+ @invoked_methods.uniq
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,12 @@
1
+ module FactoryBot
2
+ class Decorator
3
+ class NewConstructor < Decorator
4
+ def initialize(component, build_class)
5
+ super(component)
6
+ @build_class = build_class
7
+ end
8
+
9
+ delegate :new, to: :@build_class
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,136 @@
1
+ module FactoryBot
2
+ # @api private
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
12
+ @additional_traits = []
13
+ @constructor = nil
14
+ @attributes = nil
15
+ @compiled = false
16
+ end
17
+
18
+ delegate :declare_attribute, to: :declarations
19
+
20
+ def attributes
21
+ @attributes ||= AttributeList.new.tap do |attribute_list|
22
+ attribute_lists = aggregate_from_traits_and_self(:attributes) { declarations.attributes }
23
+ attribute_lists.each do |attributes|
24
+ attribute_list.apply_attributes attributes
25
+ end
26
+ end
27
+ end
28
+
29
+ def to_create(&block)
30
+ if block_given?
31
+ @to_create = block
32
+ else
33
+ aggregate_from_traits_and_self(:to_create) { @to_create }.last
34
+ end
35
+ end
36
+
37
+ def constructor
38
+ aggregate_from_traits_and_self(:constructor) { @constructor }.last
39
+ end
40
+
41
+ def callbacks
42
+ aggregate_from_traits_and_self(:callbacks) { @callbacks }
43
+ end
44
+
45
+ def compile
46
+ unless @compiled
47
+ declarations.attributes
48
+
49
+ 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 }
52
+ end
53
+
54
+ @compiled = true
55
+ end
56
+ end
57
+
58
+ def overridable
59
+ declarations.overridable
60
+ self
61
+ end
62
+
63
+ def inherit_traits(new_traits)
64
+ @base_traits += new_traits
65
+ end
66
+
67
+ def append_traits(new_traits)
68
+ @additional_traits += new_traits
69
+ end
70
+
71
+ def add_callback(callback)
72
+ @callbacks << callback
73
+ end
74
+
75
+ def skip_create
76
+ @to_create = ->(instance) { }
77
+ end
78
+
79
+ def define_trait(trait)
80
+ @defined_traits.add(trait)
81
+ end
82
+
83
+ def define_constructor(&block)
84
+ @constructor = block
85
+ end
86
+
87
+ def before(*names, &block)
88
+ callback(*names.map { |name| "before_#{name}" }, &block)
89
+ end
90
+
91
+ def after(*names, &block)
92
+ callback(*names.map { |name| "after_#{name}" }, &block)
93
+ end
94
+
95
+ def callback(*names, &block)
96
+ names.each do |name|
97
+ FactoryBot.register_callback(name)
98
+ add_callback(Callback.new(name, block))
99
+ end
100
+ end
101
+
102
+ private
103
+
104
+ def base_traits
105
+ @base_traits.map { |name| trait_by_name(name) }
106
+ end
107
+
108
+ def additional_traits
109
+ @additional_traits.map { |name| trait_by_name(name) }
110
+ end
111
+
112
+ def trait_by_name(name)
113
+ trait_for(name) || FactoryBot.trait_by_name(name)
114
+ end
115
+
116
+ def trait_for(name)
117
+ defined_traits.detect { |trait| trait.name == name }
118
+ end
119
+
120
+ def initialize_copy(source)
121
+ super
122
+ @attributes = nil
123
+ @compiled = false
124
+ end
125
+
126
+ def aggregate_from_traits_and_self(method_name, &block)
127
+ compile
128
+
129
+ [
130
+ base_traits.map(&method_name),
131
+ instance_exec(&block),
132
+ additional_traits.map(&method_name),
133
+ ].flatten.compact
134
+ end
135
+ end
136
+ end
@@ -0,0 +1,48 @@
1
+ module FactoryBot
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
14
+
15
+ def self.build_from_definition(definition)
16
+ build_to_create(&definition.to_create)
17
+ build_constructor(&definition.constructor)
18
+ add_callbacks definition.callbacks
19
+ end
20
+
21
+ def self.add_callbacks(callbacks)
22
+ if callbacks.any?
23
+ define_method :callbacks do
24
+ super() + callbacks
25
+ end
26
+ end
27
+ end
28
+ private_class_method :add_callbacks
29
+
30
+ def self.build_constructor(&block)
31
+ if block
32
+ define_method(:constructor) do
33
+ block
34
+ end
35
+ end
36
+ end
37
+ private_class_method :build_constructor
38
+
39
+ def self.build_to_create(&block)
40
+ if block
41
+ define_method(:to_create) do
42
+ block
43
+ end
44
+ end
45
+ end
46
+ private_class_method :build_to_create
47
+ end
48
+ end