class DirtySeed::Sorter

Sorts ActiveRecord models depending on their associations

Attributes

checked[RW]
counter[RW]
current[RW]
flexible_dependencies[RW]
models[R]
sorted[RW]
unsorted[RW]

Public Class Methods

new(models = []) click to toggle source

Initializes an instance @param models [Array<DirtySeed::Model>] @return [DirtySeed::Sorter]

# File lib/dirty_seed/sorter.rb, line 9
def initialize(models = [])
  @models = models
end

Public Instance Methods

sort() click to toggle source

Sorts models depending on their associations @return [Array<Class>] classes inheriting from ActiveRecord::Base @note Use procedural over fonctional -> do not use recursivity

# File lib/dirty_seed/sorter.rb, line 16
def sort
  reset
  until unsorted.empty?
    count_up || break
    self.current = unsorted.first
    sort_current
  end
  sorted
end

Private Instance Methods

count_up() click to toggle source

Updates count or return false if limite is exceeded @return [Boolean]

# File lib/dirty_seed/sorter.rb, line 43
def count_up
  return false if counter >= models.count * 5

  self.counter = counter + 1
end
dependent?(association) click to toggle source

Is the association dependent from an unsorted model? @param association [DirtySeed::Association] @return [Boolean]

# File lib/dirty_seed/sorter.rb, line 119
def dependent?(association)
  return if flexible_dependencies && association.optional?

  # When flexible_dependencies is activated, at least one polymorphic relation should be sorted
  #   Either, all polymorphic relations should be sorted
  method = flexible_dependencies ? :any? : :all?
  association.associated_models.public_send(method) do |active_record_model|
    unsorted.map(&:__getobj__).include? active_record_model
  end
end
flexible_dependencies!() click to toggle source

Activates flexible_dependencies option to prevent infinite loop @return [void]

# File lib/dirty_seed/sorter.rb, line 69
def flexible_dependencies!
  self.flexible_dependencies = true
  self.checked = Set.new
end
independent?() click to toggle source

Is current independent from any unsorted model? @return [Boolean] @example

Given a model Foo
And Foo.belongs_to(:bar)
And Foo.belongs_to(:zed, optional: true)
And Bar is sorted
And Zed is not sorted yet
If @flexible_dependencies is false (all relations should be sorted)
  Then Foo is not independent
Else (required relations should be sorted)
  Then Foo is independent

@example

Given a model Foo
And Foo.belongs_to(:fooable, polymorphic: true)
And Bar.has_many(:foos, as: :fooable)
And Zed.has_many(:foos, as: :fooable)
And Bar is sorted
And Zed is not sorted yet
If @flexible_dependencies is false (all relations should be sorted)
  Then Foo is not independent
Else (at least one relation - in case of polymorpism - should be sorted)
  Then Foo is independent
# File lib/dirty_seed/sorter.rb, line 110
def independent?
  return true if unsorted.one?

  current.associations.none? { |association| dependent?(association) }
end
insert_or_rotate() click to toggle source

Chooses if current should be added to sorted ones or not @return [void]

# File lib/dirty_seed/sorter.rb, line 76
def insert_or_rotate
  # if current is independent of any unsorted model
  if independent?
    # removed current from unsorted and add it to sorted
    sorted << unsorted.shift
  else
    # rotate models array so current will be sorted at the end
    unsorted.rotate!
  end
end
loop?() click to toggle source

Is the current model already checked? @return [Boolean]

# File lib/dirty_seed/sorter.rb, line 63
def loop?
  checked.include? current
end
reset() click to toggle source

Reset state before sorting @return [void]

# File lib/dirty_seed/sorter.rb, line 33
def reset
  self.counter = 0
  self.flexible_dependencies = false
  self.unsorted = models.clone
  self.sorted = []
  self.checked = Set.new
end
sort_current() click to toggle source

Sort the current model @return [void]

# File lib/dirty_seed/sorter.rb, line 51
def sort_current
  flexible_dependencies! if loop?
  insert_or_rotate
# rescue from errors coming from RDBMS or related
rescue StandardError
  unsorted.delete(current)
ensure
  checked << current
end