<commit_before>module Hawk
  module Model

    module Association
      # Initialize the associations registry
      #
      def self.included(base)
        base.extend ClassMethods
        base.instance_eval { @_associations ||= {} }
      end

      # Load associations early, to memoize them and avoid having
      # Hashes when a Model is more appropriate.
      #
      def initialize(attributes = {}, http_options = {})
        if attributes.size > 0 && self.class.associations?
          preload_associations(attributes, http_options, self.class)
        end

        super
      end

      private
        def preload_associations(attributes, http_options, scope)
          scope.associations.each do |name, (_, options)|
            if (repr = scope.preload_association.call(attributes, name, options))
              target = options.fetch(:class_name)

              # This is a bit naive. But it's convention over configuration.
              # And makes you architect # stuff The Right Way, not throwing
              # randomly stuff around hoping it'll magically work.
              target = scope.const_defined?(target, inherit=false) ?
                scope.const_get(target)        :
                scope.parent.const_get(target)

              result = target.instantiate_from(repr, http_options)
              instance_variable_set("@_#{name}", result)
            end
          end
        end

      module ClassMethods
        # Propagate associations to the subclasses on inheritance
        #
        def inherited(subclass)
          super

          parent = self
          subclass.instance_eval do
            # Inherit associations
            @_associations ||= {}

            parent.associations.each do |name, (type, options)|
              _define_association(name, type, options)
            end

            # Inherit association preloading behaviour
            preload_association(&parent.preload_association)
          end
        end

        # Defines how associations should be preloaded.
        #
        # The given block gets called when a new entity is instantiated, and
        # it gets passed the object attributes, the association's name, type
        # and options.
        #
        # Example (for Joe :-)
        #
        #     class Foo < Hawk::Model::Base
        #
        #       has_many :bars
        #
        #       preload_association do |attributes, name, type, options|
        #         if attributes.key?('links')
        #           links = attributes['links']
        #           if links.key?(name)
        #             return attributes.delete(links[name])
        #           end
        #         end
        #       end
        #
        #     end
        #
        # The block would get called once, with :bars as `name`, :has_many as
        # `type` and `{class_name:'Bar', primary_key:'foo_id'}` as `options`.
        #
        # By default it looks up in the representation a property named after
        # the association's name and returns it, deleting it from the repr.
        #
        def preload_association(&block)
          @_preload_association = block if block
          @_preload_association ||= lambda do |attributes, name, options|
            attr = name.to_s

            if attributes.key?(attr)
              return attributes.delete(attr)
            end
          end
        end<commit_msg>Pass along association type to preload_association @jblackman<commit_after>module Hawk
  module Model

    module Association
      # Initialize the associations registry
      #
      def self.included(base)
        base.extend ClassMethods
        base.instance_eval { @_associations ||= {} }
      end

      # Load associations early, to memoize them and avoid having
      # Hashes when a Model is more appropriate.
      #
      def initialize(attributes = {}, http_options = {})
        if attributes.size > 0 && self.class.associations?
          preload_associations(attributes, http_options, self.class)
        end

        super
      end

      private
        def preload_associations(attributes, http_options, scope)
          scope.associations.each do |name, (type, options)|
            if (repr = scope.preload_association.call(attributes, name, type, options))
              target = options.fetch(:class_name)

              # This is a bit naive. But it's convention over configuration.
              # And makes you architect # stuff The Right Way, not throwing
              # randomly stuff around hoping it'll magically work.
              target = scope.const_defined?(target, inherit=false) ?
                scope.const_get(target)        :
                scope.parent.const_get(target)

              result = target.instantiate_from(repr, http_options)
              instance_variable_set("@_#{name}", result)
            end
          end
        end

      module ClassMethods
        # Propagate associations to the subclasses on inheritance
        #
        def inherited(subclass)
          super

          parent = self
          subclass.instance_eval do
            # Inherit associations
            @_associations ||= {}

            parent.associations.each do |name, (type, options)|
              _define_association(name, type, options)
            end

            # Inherit association preloading behaviour
            preload_association(&parent.preload_association)
          end
        end

        # Defines how associations should be preloaded.
        #
        # The given block gets called when a new entity is instantiated, and
        # it gets passed the object attributes, the association's name, type
        # and options.
        #
        # Example (for Joe :-)
        #
        #     class Foo < Hawk::Model::Base
        #
        #       has_many :bars
        #
        #       preload_association do |attributes, name, type, options|
        #         if attributes.key?('links')
        #           links = attributes['links']
        #           if links.key?(name)
        #             return attributes.delete(links[name])
        #           end
        #         end
        #       end
        #
        #     end
        #
        # The block would get called once, with :bars as `name`, :has_many as
        # `type` and `{class_name:'Bar', primary_key:'foo_id'}` as `options`.
        #
        # By default it looks up in the representation a property named after
        # the association's name and returns it, deleting it from the repr.
        #
        def preload_association(&block)
          @_preload_association = block if block
          @_preload_association ||= lambda do |attributes, name, type, options|
            attr = name.to_s

            if attributes.key?(attr)
              return attributes.delete(attr)
            end
          end
        end
{'fraction_non_alphanumeric': 0.0754634359947453, 'fraction_numerical': 0.00029192818566632606, 'mean_word_length': 1.7115156311832211, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 5, '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': '217665', 'n_tokens_mistral': 1735, 'n_tokens_neox': 1684, 'n_words': 518}