Class: SelfishAssociations::PathMerger

Inherits:
Object
  • Object
show all
Defined in:
lib/selfish_associations/utils/path_merger.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(paths) ⇒ PathMerger

Returns a new instance of PathMerger.



5
6
7
# File 'lib/selfish_associations/utils/path_merger.rb', line 5

def initialize(paths)
  @paths = paths.select(&:present?)
end

Instance Attribute Details

#pathsObject (readonly)

Returns the value of attribute paths.



3
4
5
# File 'lib/selfish_associations/utils/path_merger.rb', line 3

def paths
  @paths
end

Instance Method Details

#denillify(paths) ⇒ Object

Strip off the nil endpoints in a merged nillified Hash path Array. 1-deep paths get un-Hashed. I.e., => nil becomes just key. >1-deep Hashes are guaranteed to have Hash values. So, from above,

{:a => {:b => {:c => nil}, {:x => nil}}}

now becomes

{:a => [:x, {:b => :c}]}


57
58
59
60
61
62
63
# File 'lib/selfish_associations/utils/path_merger.rb', line 57

def denillify(paths)
  singles, hashes = paths.keys.partition{|k| paths[k].nil?}
  hashes.each{|k| paths[k] = denillify(paths[k])}
  return_array = singles
  return_array << paths.slice(*hashes) if hashes.present?
  return return_array.length == 1 ? return_array.first : return_array
end

#hashify_path(path) ⇒ Object

Convert each association index array into a 1-wide, n-deep Hash For algorithmic convenience (see below), applies a nil endpoint to all paths. So

[:a, :b, :c]

becomes

{:a => {:b => {:c => nil}}}


24
25
26
# File 'lib/selfish_associations/utils/path_merger.rb', line 24

def hashify_path(path)
  path.reverse.reduce(nil){|path_partial, node| {node => path_partial}}
end

#mergeObject

Take array of arrays in @paths and turn into a nested hash Duplicate keys are collapsed into Array values Endpoint values are guaranteed to be Arrays



12
13
14
15
# File 'lib/selfish_associations/utils/path_merger.rb', line 12

def merge
  merged_paths = @paths.reduce({}){|merged, path| merge_paths(merged, hashify_path(path))}
  return denillify(merged_paths)
end

#merge_paths(paths, new_path) ⇒ Object

Merge in a new hash path into the current merged hash paths. Dup keys are combined as a merged Hash themselves: we need recursion! Non-nil values are guaranteed to be Hashes because we’ve introduced the nil endpoint Therefore we can simply merge all non-nil values recursivelye So

[[:a, :b, :c], [:a, :b], [:a, :x]

which hashifies into (remembering that we add nil endpoints)

[{:a => {:b => {:c => nil}}}, {:a => {:b => :nil}}, {:a => {:x => nil}}]

now becomes

{:a => {:b => {:c => nil}, {:x => nil}}}


38
39
40
41
42
43
44
45
46
47
48
# File 'lib/selfish_associations/utils/path_merger.rb', line 38

def merge_paths(paths, new_path)
  paths.merge!(new_path) do |parent_node, oldval, newval|
    if oldval.nil? || newval.nil?
      # If either old or new path ended at parent_node, use the other
      oldval || newval
    else
      # Else both paths continue from this node: recurse down the path!
      merge_paths(oldval, newval)
    end
  end
end