lib/eco/api/common/people/supervisor_helpers.rb in eco-helpers-2.0.15 vs lib/eco/api/common/people/supervisor_helpers.rb in eco-helpers-2.0.16

- old
+ new

@@ -13,10 +13,11 @@ module ClassMethods # Reorders as follows: # 1. supervisors, people with no supervisor or where their supervisor not present # 2. subordinates + # @return [Array<Entry>] `values` sorted by supervisors/subordinates def sort_by_supervisors(values, supervisors_first: true) raise "Expected non hash Enumerable. Given: #{values.class}" if values.is_a?(Hash) return [] unless values && values.is_a?(Enumerable) roam = Proc.new do |tree| [].tap do |out| @@ -28,9 +29,35 @@ end end end roam.call(supervisors_tree(values)) + end + + # Identifies all the cyclic supervisor chains + # @note as `supervisors_tree` will have any entry involved in a cycle at the top, it just checks all the top entries against their offspring + # @return [Array<Array>] the sets of entries that are cyclic + def identify_cyclic_chains(values) + raise "Expected non hash Enumerable. Given: #{values.class}" if values.is_a?(Hash) + return [] unless values && values.is_a?(Enumerable) + + identify = Proc.new do |top_sup, offspring, chain = [top_sup]| + next [] if offspring.empty? + offspring.each_with_object([]) do |(sup, subordinates), set| + break set unless set.empty? + if top_sup.supervisor_id == sup.id + set.concat(chain, [sup]) + else + set = identify.call(top_sup, subordinates, chain | [sup]) + end + end + end + + supervisors_tree(values).each_with_object([]) do |(top_sup, offspring), sets| + if (set = identify.call(top_sup, offspring)) && !set.empty? + sets.push(set) + end + end end def tree_to_str(tree, lev: 0) raise "Required Hash tree structure. Given: #{tree.class}" unless tree.is_a?(Hash) "".tap do |str|