Project

General

Profile

Bug #12278 ยป minuend_spec.rb

ProcsReducer#inlay_procs usage - newmen (Gleb Averchuk), 04/13/2016 06:25 PM

 
1
module VersatileDiamond
2
  module Organizers
3

    
4
    # Provides method for minuend behavior
5
    module MinuendSpec
6
      include Modules::OrderProvider
7
      include Modules::ProcsReducer
8
      include Organizers::LinksCleaner
9
      include Organizers::Minuend
10

    
11
      # Compares two minuend instances
12
      # @param [Minuend] other the comparable minuend instance
13
      # @return [Integer] the result of comparation
14
      def <=>(other)
15
        compare_with(other)
16
      end
17

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

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

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

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

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

    
57

    
58
    protected
59

    
60
      # Counts the relations number in current links
61
      # @return [Integer] the number of relations
62
      def relations_num
63
        links.values.map(&:size).reduce(:+)
64
      end
65

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

    
76
    private
77

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

    
87
        atoms_to_parents = {}
88
        residuals = rest_links(other, mirror) do |own_atom|
89
          atoms_to_parents[own_atom] = [proxy]
90
        end
91

    
92
        SpecResidual.new(owner, residuals, atoms_to_parents)
93
      end
94

    
95
      # Compares two minuend instances
96
      # @param [Minuend] other the comparable minuend instance
97
      # @option [Boolean] :strong_types_order is the flag which if set then types info
98
      #   also used for ordering
99
      # @return [Integer] the result of comparation
100
      def compare_with(other, strong_types_order: true)
101
        inlay_procs(comparing_core(other)) do |nest|
102
          nest[:order, self, other, :links, :size]
103
          nest[:order_classes, other] if strong_types_order
104
          nest[:order_relations, other]
105
        end
106
      end
107

    
108
      # Provides comparison by number of relations
109
      # @param [Minuend] other see at #<=> same argument
110
      # @return [Integer] the result of comparation
111
      def order_relations(other, &block)
112
        order(self, other, :relations_num, &block)
113
      end
114

    
115
      # Provides the lowest level of comparing two minuend instances
116
      # @param [MinuendSpec] other comparing instance
117
      # @return [Proc] the core of comparison
118
      def comparing_core(other)
119
        -> do
120
          order(self, other, :parents, :size) do
121
            order(self, other, :name) do
122
              order(self, other, :object_id)
123
            end
124
          end
125
        end
126
      end
127

    
128
      # Provides comparison by class of each instance
129
      # @param [MinuendSpec] other see at #<=> same argument
130
      # @return [Integer] the result of comparation
131
      def order_classes(other, &block)
132
        typed_order(self, other, DependentSpecificSpec) do
133
          typed_order(self, other, DependentBaseSpec) do
134
            typed_order(self, other, SpecResidual, &block)
135
          end
136
        end
137
      end
138

    
139
      # Checks that passed relation between atoms is not excess
140
      # @param [Concepts::Atom | Concepts::AtomReference | Concepts::SpecificAtom]
141
      #   neighbour_key the neighbour key of iterable key
142
      # @param [Concepts::Atom | Concepts::AtomReference | Concepts::SpecificAtom]
143
      #   checking_key the key which checks that it used
144
      # @param [Concepts::Bond] relation between iterable key and neighbour key
145
      # @return [Boolean] is realy used checking key or not
146
      def excess_neighbour?(neighbour_key, checking_key, relation)
147
        excess_position?(relation, checking_key, neighbour_key)
148
      end
149
    end
150

    
151
  end
152
end