module NoBrainer::Tree::Ordering
NoBrainer::Tree::Ordering
¶ ↑
NoBrainer::Tree
doesn’t order the tree by default. To enable ordering of children include both NoBrainer::Tree
and NoBrainer::Tree::Ordering
into your document.
Utility methods¶ ↑
This module adds methods to get related siblings depending on their position:
node.lower_siblings node.higher_siblings node.first_sibling_in_list node.last_sibling_in_list
There are several methods to move nodes around in the list:
node.move_up node.move_down node.move_to_top node.move_to_bottom node.move_above(other) node.move_below(other)
Additionally there are some methods to check aspects of the document in the list of children:
node.at_top? node.at_bottom?
Public Instance Methods
Returns a chainable criteria for this document’s ancestors
@return [NoBrainer::Criteria] NoBrainer
criteria to retrieve the document’s ancestors
# File lib/nobrainer/tree/ordering.rb, line 53 def ancestors base_class.without_index.unscoped.where(:id.in => self.parent_ids).order_by(:depth => :asc) end
Is this the lowest sibling?
@return [Boolean] Whether the document is the lowest sibling
# File lib/nobrainer/tree/ordering.rb, line 113 def at_bottom? lower_siblings.empty? end
Is this the highest sibling?
@return [Boolean] Whether the document is the highest sibling
# File lib/nobrainer/tree/ordering.rb, line 105 def at_top? higher_siblings.empty? end
Returns the highest sibling (could be self)
@return [NoBrainer::Document] The highest sibling
# File lib/nobrainer/tree/ordering.rb, line 97 def first_sibling_in_list siblings_and_self.first end
Returns siblings above the current document. Siblings with a position lower than this document’s position.
@return [NoBrainer::Criteria] NoBrainer
criteria to retrieve the document’s higher siblings
# File lib/nobrainer/tree/ordering.rb, line 71 def higher_siblings self.siblings.where(:position.lt => self.position) end
# File lib/nobrainer/tree/ordering.rb, line 45 def inc(increments) update(increments.symbolize_keys.map{ |field, value| { field => (self[field] || 0) + value } }.first) end
Returns the lowest sibling (could be self)
@return [NoBrainer::Document] The lowest sibling
# File lib/nobrainer/tree/ordering.rb, line 89 def last_sibling_in_list siblings_and_self.last end
Returns siblings below the current document. Siblings with a position greater than this document’s position.
@return [NoBrainer::Criteria] NoBrainer
criteria to retrieve the document’s lower siblings
# File lib/nobrainer/tree/ordering.rb, line 62 def lower_siblings self.siblings.where(:position.gt => self.position) end
Move this node above the specified node
This method changes the node’s parent if nescessary.
@param [NoBrainer::Tree] other document to move this document above
@return [undefined]
# File lib/nobrainer/tree/ordering.rb, line 159 def move_above(other) ensure_to_be_sibling_of(other) if position > other.position new_position = other.position self.siblings_between(other).each{ |object| object.inc(:position => 1) } other.inc(:position => 1) else new_position = other.position - 1 self.siblings_between(other).each{ |object| object.inc(:position => -1) } end self.position = new_position save end
Move this node below the specified node
This method changes the node’s parent if nescessary.
@param [NoBrainer::Tree] other document to move this document below
@return [undefined]
# File lib/nobrainer/tree/ordering.rb, line 183 def move_below(other) ensure_to_be_sibling_of(other) if position > other.position new_position = other.position + 1 self.siblings_between(other).each{ |object| object.inc(:position => 1) } else new_position = other.position self.siblings_between(other).each{ |object| object.inc(:position => -1) } other.inc(:position => -1) end self.position = new_position save end
Move this node one position down
@return [undefined]
# File lib/nobrainer/tree/ordering.rb, line 147 def move_down switch_with_sibling_at_offset(1) unless at_bottom? end
Move this node below all its siblings
@return [undefined]
# File lib/nobrainer/tree/ordering.rb, line 130 def move_to_bottom return true if at_bottom? move_below(last_sibling_in_list) end
Move this node above all its siblings
@return [undefined]
# File lib/nobrainer/tree/ordering.rb, line 121 def move_to_top return true if at_top? move_above(first_sibling_in_list) end
Move this node one position up
@return [undefined]
# File lib/nobrainer/tree/ordering.rb, line 139 def move_up switch_with_sibling_at_offset(-1) unless at_top? end
Returns siblings between the current document and the other document Siblings with a position between this document’s position and the other document’s position.
@return [NoBrainer::Criteria] NoBrainer
criteria to retrieve the documents between this and the other document
# File lib/nobrainer/tree/ordering.rb, line 80 def siblings_between(other) range = [self.position, other.position].sort self.siblings.where(:position.gt => range.first, :position.lt => range.last) end
Private Instance Methods
# File lib/nobrainer/tree/ordering.rb, line 227 def assign_default_position self.position = self.last_sibling_in_list.position + 1 rescue 0 end
# File lib/nobrainer/tree/ordering.rb, line 231 def assign_default_position? self.position.nil? || self.parent_id_changed? end
# File lib/nobrainer/tree/ordering.rb, line 206 def ensure_to_be_sibling_of(other) return if sibling_of?(other) self.parent_id = other.parent_id save end
# File lib/nobrainer/tree/ordering.rb, line 212 def move_lower_siblings_up lower_siblings.each{ |object| object.inc(:position => -1) } end
# File lib/nobrainer/tree/ordering.rb, line 216 def reposition_former_siblings former_siblings = base_class.where(:parent_id => self.parent_id_was). where(:position.gt => (self.position_was || 0)). where(:id.ne => self.id) former_siblings.to_a.each{ |object| object.inc(:position => -1) } end
# File lib/nobrainer/tree/ordering.rb, line 223 def sibling_reposition_required? parent_id_changed? && persisted? end
# File lib/nobrainer/tree/ordering.rb, line 201 def switch_with_sibling_at_offset(offset) siblings.where(:position => self.position + offset).first.inc(:position => -offset) inc(:position => offset) end