<commit_before>require 'active_support/concern'

module RailsDynamicAssociations::ActiveRecord
	module Relations
		extend ActiveSupport::Concern

		included do
			extend  ClassAndInstanceMethods
			include ClassAndInstanceMethods
		end

		module ClassMethods
			RailsDynamicAssociations.opposite_directions.each &-> (association, method) do
				define_method "#{association}_relations" do
					Relation.send method, self
				end
			end
		end

		module ClassAndInstanceMethods
			def relative? args = {}
				find_relations(args).
					present?
			end

			def relatives args = {}
				find_relations(args).
					map { |r|
						# TODO: optimize queries
						(RailsDynamicAssociations.directions.keys.map { |d| r.send d } - [ self ]).first
					}.uniq
			end

			protected

			# TODO: use keyword arguments
			# TODO: simplify
			def find_relations args = {}
				directions = RailsDynamicAssociations.directions

				# Rearrange arguments
				for direction, method in directions do
					args[direction] = args.delete method
				end

				relations = directions.keys.each_with_object({}) do |(direction), relations|
					relations[direction] = find_relations_with_direction(*[
						direction, args.include?(:as) ? [ args[:as] ].flatten : nil
					].compact)
				end

				if direction = directions.keys.find { |a| args[a] } then # direction specified
					relations[direction].send(
						directions[direction], args[direction] # apply a filtering scope
					)
				else # both directions
					relations.values.sum
				end
			end

			private

			def find_relations_with_direction direction, roles = []
				if respond_to? association = "#{direction}_relations" then
					send(association).named roles
				else
					Relation.none<commit_msg>API: use `(to|of): nil` to get objects of any class in `#find_relations` & friends.<commit_after>require 'active_support/concern'

module RailsDynamicAssociations::ActiveRecord
	module Relations
		extend ActiveSupport::Concern

		included do
			extend  ClassAndInstanceMethods
			include ClassAndInstanceMethods
		end

		module ClassMethods
			RailsDynamicAssociations.opposite_directions.each &-> (association, method) do
				define_method "#{association}_relations" do
					Relation.send method, self
				end
			end
		end

		module ClassAndInstanceMethods
			def relative? args = {}
				find_relations(args).
					present?
			end

			def relatives args = {}
				find_relations(args).
					map { |r|
						# TODO: optimize queries
						(RailsDynamicAssociations.directions.keys.map { |d| r.send d } - [ self ]).first
					}.uniq
			end

			protected

			# TODO: use keyword arguments
			def find_relations args = {}
				directions = RailsDynamicAssociations.directions

				# Rearrange arguments
				for direction, method in directions do
					args[direction] = args.delete method if
						method.in? args
				end

				roles = :as.in?(args) ?
					[ args[:as] ].flatten :
					[]

				if direction = directions.keys.find { |a| a.in? args } then # direction specified
					find_relations_with_direction(direction, roles).send(
						directions[direction], args[direction] # apply a filtering scope
					)
				else # both directions
					directions.keys.map do |direction|
						find_relations_with_direction direction, roles
					end.sum
				end
			end

			private

			def find_relations_with_direction direction, roles = []
				if respond_to? association = "#{direction}_relations" then
					send(association).named roles
				else
					Relation.none
{'fraction_non_alphanumeric': 0.08495981630309989, 'fraction_numerical': 0.0, 'mean_word_length': 3.234507897934386, 'pattern_counts': {'":': 0, '<': 3, '<?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': '6342953', 'n_tokens_mistral': 1330, 'n_tokens_neox': 970, 'n_words': 266}