class Modelist::PathFinder

Public Class Methods

back(current_node_list, counts, processed_result_partials, from) click to toggle source
# File lib/modelist/path_finder.rb, line 136
def self.back(current_node_list, counts, processed_result_partials, from)
  current_node_list.pop
  
  # if there is a count in the array less than two, keep removing them until they are gone
  while counts.last && counts.last < 2
    counts.pop
    c = current_node_list.pop

    # if this is direct/indirect circular reference, don't mark unprocessed origin as processed, because it isn't
    unless counts.size > 1 && c.start_with?("#{from}.")
      # completely processed this path, so don't process it again, and don't overwrite existing success if cached
      #puts "marking #{c} as done"
      processed_result_partials[c] = [] unless processed_result_partials[c]
    end
  end
  
  # either there are no counts, or we just need to decrement the last count
  if counts.last && counts.last > 1
    counts[counts.length-1] = counts[counts.length-1] - 1
  end
end
cache_found_path_partials(found_path_arr, cache) click to toggle source
# File lib/modelist/path_finder.rb, line 158
def self.cache_found_path_partials(found_path_arr, cache)
  (found_path_arr.length-2).downto(0) do |i|
    cache[found_path_arr[i]] = found_path_arr[i+1..found_path_arr.length-1] if found_path_arr.length > 1
  end
end
clean_underscore(classname) click to toggle source
# File lib/modelist/path_finder.rb, line 4
def self.clean_underscore(classname)
  classname = classname[2..classname.length] if classname.start_with?('::')
  classname.underscore
end
find_all(*args) click to toggle source
# File lib/modelist/path_finder.rb, line 9
def self.find_all(*args)
  raise ArgumentError.new("Please supply a search term") unless args.size != 0
  # less-dependent extract_options!
  options = args.last.is_a?(Hash) ? args.pop : {}
  
  from = args[0]
  to = args[1]

  puts "Checking for path from #{from} to #{to}..."
  relations = relationship_map_excluding(to)

  results = get_all_paths_via_iterative_depth_first_search(from, to, relations)
  puts
  puts

  matching_results = results.sort_by(&:length).reverse.collect{|arr|format_result_string(arr)}
  #TODO: make it actually not even search past N nodes
  if matching_results.length > 0
    puts "Paths from #{from} to #{to} (#{matching_results.length}):"
    # show the shortest path as the last item logged, for ease of use in CLI
    matching_results.each do |r|
      puts
      puts r
    end      
  else
    puts "No path found from #{from} to #{to}."
  end
  results
end
format_result_string(*args) click to toggle source
# File lib/modelist/path_finder.rb, line 164
def self.format_result_string(*args)
  args.flatten.join(' -> ')
end
forward(current_node_list, this_class_assoc, counts, children_count) click to toggle source
# File lib/modelist/path_finder.rb, line 131
def self.forward(current_node_list, this_class_assoc, counts, children_count)
  current_node_list.push(this_class_assoc)
  counts.push(children_count)
end
get_classname(association) click to toggle source
# File lib/modelist/path_finder.rb, line 168
def self.get_classname(association)
  association.options[:class_name] || case association.macro
  when :belongs_to, :has_one
    association.name.to_s
  when :has_and_belongs_to_many, :has_many
    association.name.to_s.singularize
  end
end
relationship_map_excluding(exclude_name) click to toggle source
# File lib/modelist/path_finder.rb, line 39
def self.relationship_map_excluding(exclude_name)
  Rails.application.eager_load!
  relations = {}
  
  m_to_a = {}
  ActiveRecord::Base.descendants.each do |m|
    m_to_a[m] = m.reflect_on_all_associations
  end

  m_to_a.each do |m,as|
    # don't try to link via composite primary keys until that is possible, which it isn't now afaik.
    next if m.primary_key.is_a?(Array)
    as.each do |association|
      c1_name = clean_underscore(m.name)
      next if c1_name == exclude_name
      #TODO: we could exclude c1/key that is "to"
      c1 = "#{c1_name}.#{association.name}"
      c2 = get_classname(association)
      if c2
        relations[c1] = clean_underscore(c2)
      end
    end unless as == nil
  end
  relations
end