class FactoryBot::AttributeAssigner
@api private
Public Class Methods
Source
# File lib/factory_bot/attribute_assigner.rb, line 4 def initialize(evaluator, build_class, &instance_builder) @build_class = build_class @instance_builder = instance_builder @evaluator = evaluator @attribute_list = evaluator.class.attribute_list @attribute_names_assigned = [] end
Public Instance Methods
Source
# File lib/factory_bot/attribute_assigner.rb, line 24 def hash @evaluator.instance = build_hash attributes_to_set_on_hash.each_with_object({}) do |attribute, result| result[attribute] = get(attribute) end end
constructs a Hash-based factory product
Source
# File lib/factory_bot/attribute_assigner.rb, line 13 def object @evaluator.instance = build_class_instance build_class_instance.tap do |instance| attributes_to_set_on_instance.each do |attribute| instance.public_send(:"#{attribute}=", get(attribute)) @attribute_names_assigned << attribute end end end
constructs an object-based factory product
Private Instance Methods
Source
# File lib/factory_bot/attribute_assigner.rb, line 93 def association_names @attribute_list.associations.names end
Source
# File lib/factory_bot/attribute_assigner.rb, line 101 def attribute_names @attribute_list.names end
Source
# File lib/factory_bot/attribute_assigner.rb, line 110 def attribute_names_overriden_by_alias @attribute_list .non_ignored .flat_map { |attribute| override_names.map do |override| attribute.name if ignorable_alias?(attribute, override) end } .compact end
Builds a list of attribute names which are slated to be interrupted by an override.
Source
# File lib/factory_bot/attribute_assigner.rb, line 75 def attribute_names_to_assign @attribute_names_to_assign ||= begin # start a list of candidates containing non-transient attributes and overrides assignment_candidates = non_ignored_attribute_names + override_names # then remove any transient attributes (potentially reintroduced by the overrides), # and remove ignorable aliased attributes from the candidate list assignment_candidates - ignored_attribute_names - attribute_names_overriden_by_alias end end
Builds a list of attributes names that should be assigned to the factory product
Source
# File lib/factory_bot/attribute_assigner.rb, line 70 def attributes_to_set_on_hash attribute_names_to_assign - association_names end
Source
# File lib/factory_bot/attribute_assigner.rb, line 66 def attributes_to_set_on_instance (attribute_names_to_assign - @attribute_names_assigned - methods_invoked_on_evaluator).uniq end
Source
# File lib/factory_bot/attribute_assigner.rb, line 54 def build_class_instance @build_class_instance ||= method_tracking_evaluator.instance_exec(&@instance_builder) end
Source
# File lib/factory_bot/attribute_assigner.rb, line 58 def build_hash @build_hash ||= NullObject.new(hash_instance_methods_to_respond_to) end
Source
# File lib/factory_bot/attribute_assigner.rb, line 43 def decorated_evaluator Decorator::NewConstructor.new( Decorator::InvocationTracker.new(@evaluator), @build_class ) end
Source
# File lib/factory_bot/attribute_assigner.rb, line 62 def get(attribute_name) @evaluator.send(attribute_name) end
Source
# File lib/factory_bot/attribute_assigner.rb, line 105 def hash_instance_methods_to_respond_to attribute_names + override_names + @build_class.instance_methods end
Source
# File lib/factory_bot/attribute_assigner.rb, line 128 def ignorable_alias?(attribute, override) return false unless attribute.alias_for?(override) # The attribute alias should be ignored when the override interrupts an association return true if override_interrupts_association?(attribute, override) # Remaining aliases should be ignored when the override does not match a declared attribute. # An override which is an alias to a declared attribute should not interrupt the aliased # attribute and interrupt only the attribute with a matching name. This workaround allows a # factory to declare both <attribute> and <attribute>_id as separate and distinct attributes. !override_matches_declared_attribute?(override) end
Is the attribute an ignorable alias of the override? An attribute is ignorable when it is an alias of the override AND it is either interrupting an assocciation OR is not the name of another attribute
@note An “alias” is currently an overloaded term for two distinct cases:
(1) attributes which are aliases and reference the same value (2) a logical grouping of a foreign key and an associated object
Source
# File lib/factory_bot/attribute_assigner.rb, line 89 def ignored_attribute_names @attribute_list.ignored.names end
Source
# File lib/factory_bot/attribute_assigner.rb, line 36 def method_tracking_evaluator @method_tracking_evaluator ||= Decorator::AttributeHash.new( decorated_evaluator, attribute_names_to_assign ) end
Track evaluation of methods on the evaluator to prevent the duplicate assignment of attributes accessed and via ‘initialize_with` syntax
Source
# File lib/factory_bot/attribute_assigner.rb, line 50 def methods_invoked_on_evaluator method_tracking_evaluator.__invoked_methods__ end
Source
# File lib/factory_bot/attribute_assigner.rb, line 85 def non_ignored_attribute_names @attribute_list.non_ignored.names end
Source
# File lib/factory_bot/attribute_assigner.rb, line 152 def override_interrupts_association?(aliased_attribute, override) (aliased_attribute.association? || association_names.include?(override)) && aliased_attribute.name != override end
Does this override interrupt an association? When true, this indicates the aliased attribute is related to a declared association and the override does not match the attribute name.
@note Association overrides should take precedence over a declared foreign key attribute.
@note An override may interrupt an association by providing the associated object or
by providing the foreign key.
@param [FactoryBot::Attribute] aliased_attribute @param [Symbol] override name of an override which is an alias to the attribute name
Source
# File lib/factory_bot/attribute_assigner.rb, line 164 def override_matches_declared_attribute?(override) attribute_names.include?(override) end
Does this override match the name of any declared attribute?
@note Checking against the names of all attributes, resolves any issues with having both
<attribute> and <attribute>_id in the same factory. This also takes into account ignored attributes that should not be assigned (aka transient attributes)
@param [Symbol] override the name of an override
Source
# File lib/factory_bot/attribute_assigner.rb, line 97 def override_names @evaluator.__override_names__ end