File: attribute_assigner.rb

package info (click to toggle)
ruby-factory-bot 6.5.1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 1,372 kB
  • sloc: ruby: 7,827; makefile: 6
file content (112 lines) | stat: -rw-r--r-- 2,896 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
module FactoryBot
  # @api private
  class AttributeAssigner
    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

    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

    def hash
      @evaluator.instance = build_hash

      attributes_to_set_on_hash.each_with_object({}) do |attribute, result|
        result[attribute] = get(attribute)
      end
    end

    private

    def method_tracking_evaluator
      @method_tracking_evaluator ||= Decorator::AttributeHash.new(
        decorated_evaluator,
        attribute_names_to_assign
      )
    end

    def decorated_evaluator
      Decorator::NewConstructor.new(
        Decorator::InvocationTracker.new(@evaluator),
        @build_class
      )
    end

    def methods_invoked_on_evaluator
      method_tracking_evaluator.__invoked_methods__
    end

    def build_class_instance
      @build_class_instance ||= method_tracking_evaluator.instance_exec(&@instance_builder)
    end

    def build_hash
      @build_hash ||= NullObject.new(hash_instance_methods_to_respond_to)
    end

    def get(attribute_name)
      @evaluator.send(attribute_name)
    end

    def attributes_to_set_on_instance
      (attribute_names_to_assign - @attribute_names_assigned - methods_invoked_on_evaluator).uniq
    end

    def attributes_to_set_on_hash
      attribute_names_to_assign - association_names
    end

    def attribute_names_to_assign
      @attribute_names_to_assign ||=
        non_ignored_attribute_names +
        override_names -
        ignored_attribute_names -
        alias_names_to_ignore
    end

    def non_ignored_attribute_names
      @attribute_list.non_ignored.names
    end

    def ignored_attribute_names
      @attribute_list.ignored.names
    end

    def association_names
      @attribute_list.associations.names
    end

    def override_names
      @evaluator.__override_names__
    end

    def hash_instance_methods_to_respond_to
      @attribute_list.names + override_names + @build_class.instance_methods
    end

    def alias_names_to_ignore
      @attribute_list.non_ignored.flat_map { |attribute|
        override_names.map do |override|
          attribute.name if ignorable_alias?(attribute, override)
        end
      }.compact
    end

    def ignorable_alias?(attribute, override)
      attribute.alias_for?(override) &&
        attribute.name != override &&
        !ignored_attribute_names.include?(override)
    end
  end
end