<commit_before># frozen_string_literal: true
module IdentityCache
  module Cached
    module Recursive
      class Association < Cached::Association # :nodoc:
        def initialize(name, reflection:)
          super
          @dehydrated_variable_name = :"@dehydrated_#{name}"
        end

        attr_reader :dehydrated_variable_name

        def build
          reflection.active_record.class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
            def #{cached_accessor_name}
              fetch_recursively_cached_association(
                :#{records_variable_name},
                :#{dehydrated_variable_name},
                :#{name}
              )
            end
          RUBY

          ParentModelExpiration.add_parent_expiry_hook(self)
        end

        def read(record)
          record.public_send(cached_accessor_name)
        end

        def write(record, records)
          record.instance_variable_set(records_variable_name, records)
        end

        def clear(record)
          if record.instance_variable_defined?(records_variable_name)
            record.remove_instance_variable(records_variable_name)
          end
        end

        def fetch(records)
          fetch_async(LoadStrategy::Eager, records) { |child_records| child_records }
        end

        def fetch_async(load_strategy, records)
          fetch_embedded_async(load_strategy, records) do
            yield records.flat_map(&cached_accessor_name).tap(&:compact!)
          end
        end

        def embedded_by_reference?
          false
        end

        def embedded_recursively?
          true
        end

        private

        def embedded_fetched?(records)
          record = records.first
          super || record.instance_variable_defined?(dehydrated_variable_name)
        end
      end
    end
  end
end
<commit_msg>Use define_method instead of class_eval in cached recursive association<commit_after># frozen_string_literal: true
module IdentityCache
  module Cached
    module Recursive
      class Association < Cached::Association # :nodoc:
        def initialize(name, reflection:)
          super
          @dehydrated_variable_name = :"@dehydrated_#{name}"
        end

        attr_reader :dehydrated_variable_name

        def build
          cached_association = self

          model = reflection.active_record
          model.send(:define_method, cached_accessor_name) do
            fetch_recursively_cached_association(
              cached_association.records_variable_name,
              cached_association.dehydrated_variable_name,
              cached_association.name
            )
          end

          ParentModelExpiration.add_parent_expiry_hook(self)
        end

        def read(record)
          record.public_send(cached_accessor_name)
        end

        def write(record, records)
          record.instance_variable_set(records_variable_name, records)
        end

        def clear(record)
          if record.instance_variable_defined?(records_variable_name)
            record.remove_instance_variable(records_variable_name)
          end
        end

        def fetch(records)
          fetch_async(LoadStrategy::Eager, records) { |child_records| child_records }
        end

        def fetch_async(load_strategy, records)
          fetch_embedded_async(load_strategy, records) do
            yield records.flat_map(&cached_accessor_name).tap(&:compact!)
          end
        end

        def embedded_by_reference?
          false
        end

        def embedded_recursively?
          true
        end

        private

        def embedded_fetched?(records)
          record = records.first
          super || record.instance_variable_defined?(dehydrated_variable_name)
        end
      end
    end
  end
end

{'fraction_non_alphanumeric': 0.05874569992061392, 'fraction_numerical': 0.0002646202699126753, 'mean_word_length': 2.1059983566146263, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2553396', 'n_tokens_mistral': 1039, 'n_tokens_neox': 987, 'n_words': 192}