newmen/versatile-diamond

View on GitHub
analyzer/lib/organizers/minuend_spec.rb

Summary

Maintainability
A
0 mins
Test Coverage
module VersatileDiamond
  module Organizers

    # Provides method for minuend behavior
    module MinuendSpec
      include Modules::OrderProvider
      include Modules::ProcsReducer
      include Organizers::LinksCleaner
      include Organizers::Minuend

      # Compares two minuend instances
      # @param [Minuend] other the comparable minuend instance
      # @return [Integer] the result of comparation
      def <=>(other)
        compare_with(other)
      end

      # Checks that current instance is less than other
      # @param [Minuend] other the comparable minuend instance
      # @return [Boolean] is less or not
      def <(other)
        compare_with(other, strong_types_order: false) < 0
      end

      # Checks that current instance is less than other or equal
      # @param [Minuend] other the comparable minuend instance
      # @return [Boolean] is less or equal or not
      def <=(other)
        self == other || self < other
      end

      # Provides relations of atom in current resudual
      # @param [Concepts::Atom | Concepts::AtomRelation] atom for which relations will
      #   be got
      # @option [Boolean] :with_atoms if true, then relations will contain neighbour
      #   atoms too
      # @return [Array] the array of atom relations
      def relations_of(atom, with_atoms: false)
        relations = links[atom]
        with_atoms ? relations : relations.map(&:last)
      end

      # Removes excess positions from current links graph
      # @return [Hash] the links of concept specie without excess positions
      def clean_links
        @_clean_links ||= erase_excess_positions(cleanable_links)
      end

      # Finds first intersec with some spec
      # @param [DependentBaseSpec] spec the checkable specie
      # @return [Array] the array of each pair of intersection or nil if intersection
      #   have not fond
      def mirror_to(spec)
        Mcs::SpeciesComparator.make_mirror(self, spec)
      end

    protected

      # Counts the relations number in current links
      # @return [Integer] the number of relations
      def relations_num
        erase_excess_positions(links).values.map(&:size).reduce(:+)
      end

      # Gets the array of used relations without excess position relations
      # @param [Atom] atom see at #relations_of same argument
      # @return [Array] the array of relations without excess position relations
      def used_relations_of(atom)
        pairs = relations_of(atom, with_atoms: true).reject do |a, r|
          excess_position?(r, atom, a)
        end
        pairs.map(&:last)
      end

    private

      # Makes residual of difference between top and possible parent
      # @param [DependentBaseSpec | DependentSpecificSpec] other the subtrahend spec
      # @param [Hash] mirror from self to other spec
      # @return [SpecResidual] the residual of diference between arguments or nil if
      #   it doesn't exist
      def subtract(other, mirror)
        # the proxy should be maked just one time
        proxy = ProxyParentSpec.new(other, owner, mirror)

        atoms_to_parents = {}
        residuals = rest_links(other, mirror) do |own_atom|
          atoms_to_parents[own_atom] = [proxy]
        end

        SpecResidual.new(owner, residuals, atoms_to_parents)
      end

      # Compares two minuend instances
      # @param [Minuend] other the comparable minuend instance
      # @param [Hash] kwargs
      # @return [Integer] the result of comparation
      def compare_with(other, **kwargs)
        core_proc = -> { comparing_core(other) }
        inlay_procs(core_proc) do |nest|
          inlay_orders(nest, other, **kwargs)
        end
      end

      # Provides the first checking order between self and other minuends
      # @param [Proc] nest to which the call will be nested
      # @param [Minuend] other comparing item
      # @option [Boolean] :strong_types_order is the flag which if set then types info
      #   also used for ordering
      def inlay_orders(nest, other, strong_types_order: true)
        nest[:order_classes, other] if strong_types_order
        nest[:order, self, other, :relations_num]
        nest[:order, self, other, :links, :size]
      end

      # Provides the lowest level of comparing two minuend instances
      # @param [MinuendSpec] other comparing instance
      # @return [Integer] the result of comparation
      def comparing_core(other)
        order(self, other, :parents, :size) do
          order(self, other, :name)
        end
      end

      # Provides comparison by class of each instance
      # @param [MinuendSpec] other see at #<=> same argument
      # @return [Integer] the result of comparation
      def order_classes(other, &block)
        typed_order(self, other, DependentSpecificSpec) do
          typed_order(self, other, DependentBaseSpec) do
            typed_order(self, other, SpecResidual, &block)
          end
        end
      end

      # Gets the links without excess positions
      # @param [Hash] links between atoms
      # @return [Hash] the links without excess positions
      # @override
      def erase_excess_positions(links)
        erase_excess_relations_if(super(links)) do |_, v, w|
          excess_parent_relation?(v, w)
        end
      end

      # Checks that passed relation between atoms is not excess
      # @param [Concepts::Atom | Concepts::AtomReference | Concepts::SpecificAtom]
      #   neighbour_key the neighbour key of iterable key
      # @param [Concepts::Atom | Concepts::AtomReference | Concepts::SpecificAtom]
      #   checking_key the key which checks that it used
      # @param [Concepts::Bond] relation between iterable key and neighbour key
      # @return [Boolean] is realy used checking key or not
      def excess_neighbour?(neighbour_key, checking_key, relation)
        excess_position?(relation, checking_key, neighbour_key)
      end
    end

  end
end