Module: CollectiveIdea::Acts::NestedSet::InstanceMethods

Defined in:
lib/awesome_nested_set.rb

Overview

Any instance method that returns a collection makes use of Rails 2.1’s named_scope (which is bundled for Rails 2.0), so it can be treated as a finder.

category.self_and_descendants.count
category.ancestors.find(:all, :conditions => "name like '%foo%'")

Instance Method Summary collapse

Instance Method Details

#<=>(x) ⇒ Object

order by left column



305
306
307
# File 'lib/awesome_nested_set.rb', line 305

def <=>(x)
  left <=> x.left
end

#==(comparison_object) ⇒ Object

Redefine to act like active record



310
311
312
313
314
315
# File 'lib/awesome_nested_set.rb', line 310

def ==(comparison_object)
  comparison_object.equal?(self) ||
    (comparison_object.instance_of?(self.class) &&
      comparison_object.id == id &&
      !comparison_object.new_record?)
end

#ancestorsObject

Returns an array of all parents



328
329
330
# File 'lib/awesome_nested_set.rb', line 328

def ancestors
  without_self self_and_ancestors
end

#child?Boolean

Returns true is this is a child node

Returns:

  • (Boolean)


300
301
302
# File 'lib/awesome_nested_set.rb', line 300

def child?
  !parent_id.nil?
end

#descendantsObject

Returns a set of all of its children and nested children



359
360
361
# File 'lib/awesome_nested_set.rb', line 359

def descendants
  without_self self_and_descendants
end

#is_ancestor_of?(other) ⇒ Boolean

Returns:

  • (Boolean)


371
372
373
# File 'lib/awesome_nested_set.rb', line 371

def is_ancestor_of?(other)
  self.left < other.left && other.left < self.right && same_scope?(other)
end

#is_descendant_of?(other) ⇒ Boolean

Returns:

  • (Boolean)


363
364
365
# File 'lib/awesome_nested_set.rb', line 363

def is_descendant_of?(other)
  other.left < self.left && self.left < other.right && same_scope?(other)
end

#is_or_is_ancestor_of?(other) ⇒ Boolean

Returns:

  • (Boolean)


375
376
377
# File 'lib/awesome_nested_set.rb', line 375

def is_or_is_ancestor_of?(other)
  self.left <= other.left && other.left < self.right && same_scope?(other)
end

#is_or_is_descendant_of?(other) ⇒ Boolean

Returns:

  • (Boolean)


367
368
369
# File 'lib/awesome_nested_set.rb', line 367

def is_or_is_descendant_of?(other)
  other.left <= self.left && self.left < other.right && same_scope?(other)
end

#leaf?Boolean

Returns:

  • (Boolean)


295
296
297
# File 'lib/awesome_nested_set.rb', line 295

def leaf?
  !new_record? && right - left == 1
end

#leavesObject

Returns a set of all of its nested children which do not have children



343
344
345
# File 'lib/awesome_nested_set.rb', line 343

def leaves
  descendants.where("#{self.class.quoted_table_name}.#{quoted_right_column_name} - #{self.class.quoted_table_name}.#{quoted_left_column_name} = 1")
end

#leftObject

Value of the left column



281
282
283
# File 'lib/awesome_nested_set.rb', line 281

def left
  self[left_column_name]
end

#left_siblingObject

Find the first sibling to the left



387
388
389
390
# File 'lib/awesome_nested_set.rb', line 387

def left_sibling
  siblings.find(:first, :conditions => ["#{self.class.quoted_table_name}.#{quoted_left_column_name} < ?", left],
    :order => "#{self.class.quoted_table_name}.#{quoted_left_column_name} DESC")
end

#levelObject

Returns the level of this object in the tree root level is 0



349
350
351
# File 'lib/awesome_nested_set.rb', line 349

def level
  parent_id.nil? ? 0 : ancestors.count
end

#move_leftObject

Shorthand method for finding the left sibling and moving to the left of it.



398
399
400
# File 'lib/awesome_nested_set.rb', line 398

def move_left
  move_to_left_of left_sibling
end

#move_possible?(target) ⇒ Boolean

Returns:

  • (Boolean)


427
428
429
430
431
432
433
# File 'lib/awesome_nested_set.rb', line 427

def move_possible?(target)
  self != target && # Can't target self
  same_scope?(target) && # can't be in different scopes
  # !(left..right).include?(target.left..target.right) # this needs tested more
  # detect impossible move
  !((left <= target.left && right >= target.left) or (left <= target.right && right >= target.right))
end

#move_rightObject

Shorthand method for finding the right sibling and moving to the right of it.



403
404
405
# File 'lib/awesome_nested_set.rb', line 403

def move_right
  move_to_right_of right_sibling
end

#move_to_child_of(node) ⇒ Object

Move the node to the child of another node (you can pass id only)



418
419
420
# File 'lib/awesome_nested_set.rb', line 418

def move_to_child_of(node)
  move_to node, :child
end

#move_to_left_of(node) ⇒ Object

Move the node to the left of another node (you can pass id only)



408
409
410
# File 'lib/awesome_nested_set.rb', line 408

def move_to_left_of(node)
  move_to node, :left
end

#move_to_right_of(node) ⇒ Object

Move the node to the left of another node (you can pass id only)



413
414
415
# File 'lib/awesome_nested_set.rb', line 413

def move_to_right_of(node)
  move_to node, :right
end

#move_to_rootObject

Move the node to root nodes



423
424
425
# File 'lib/awesome_nested_set.rb', line 423

def move_to_root
  move_to nil, :root
end

#parent_idObject

Value of the parent column



276
277
278
# File 'lib/awesome_nested_set.rb', line 276

def parent_id
  self[parent_column_name]
end

#rightObject

Value of the right column



286
287
288
# File 'lib/awesome_nested_set.rb', line 286

def right
  self[right_column_name]
end

#right_siblingObject

Find the first sibling to the right



393
394
395
# File 'lib/awesome_nested_set.rb', line 393

def right_sibling
  siblings.find(:first, :conditions => ["#{self.class.quoted_table_name}.#{quoted_left_column_name} > ?", left])
end

#rootObject

Returns root



318
319
320
# File 'lib/awesome_nested_set.rb', line 318

def root
  self_and_ancestors.first
end

#root?Boolean

Returns true if this is a root node.

Returns:

  • (Boolean)


291
292
293
# File 'lib/awesome_nested_set.rb', line 291

def root?
  parent_id.nil?
end

#same_scope?(other) ⇒ Boolean

Check if other model is in the same scope

Returns:

  • (Boolean)


380
381
382
383
384
# File 'lib/awesome_nested_set.rb', line 380

def same_scope?(other)
  Array(acts_as_nested_set_options[:scope]).all? do |attr|
    self.send(attr) == other.send(attr)
  end
end

#self_and_ancestorsObject

Returns the array of all parents and self



323
324
325
# File 'lib/awesome_nested_set.rb', line 323

def self_and_ancestors
  nested_set_scope.where(["#{self.class.quoted_table_name}.#{quoted_left_column_name} <= ? AND #{self.class.quoted_table_name}.#{quoted_right_column_name} >= ?", left, right])
end

#self_and_descendantsObject

Returns a set of itself and all of its nested children



354
355
356
# File 'lib/awesome_nested_set.rb', line 354

def self_and_descendants
  nested_set_scope.where(["#{self.class.quoted_table_name}.#{quoted_left_column_name} >= ? AND #{self.class.quoted_table_name}.#{quoted_right_column_name} <= ?", left, right])
end

#self_and_siblingsObject

Returns the array of all children of the parent, including self



333
334
335
# File 'lib/awesome_nested_set.rb', line 333

def self_and_siblings
  nested_set_scope.where({parent_column_name => parent_id})
end

#siblingsObject

Returns the array of all children of the parent, except self



338
339
340
# File 'lib/awesome_nested_set.rb', line 338

def siblings
  without_self self_and_siblings
end

#to_textObject



435
436
437
438
439
# File 'lib/awesome_nested_set.rb', line 435

def to_text
  self_and_descendants.map do |node|
    "#{'*'*(node.level+1)} #{node.id} #{node.to_s} (#{node.parent_id}, #{node.left}, #{node.right})"
  end.join("\n")
end

#traverse(flat = false, mover = nil, descendants = nil, level = self.level, &block) ⇒ Object

Returns self and its descendants as a nested array. If flat is true then a flat array is returned instead. Specify mover to exclude any impossible moves. Pass a block to perform an operation on each item. The block arguments are |item, descendants, level|. The remaining arguments for this method are for recursion and should not normally be given.



447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
# File 'lib/awesome_nested_set.rb', line 447

def traverse(flat = false, mover = nil, descendants = nil, level = self.level, &block)
  descendants ||= self.descendants
  array = []

  while not descendants.empty?
    break unless descendants.first.parent_id == self.id
    item = descendants.shift
    items = item.traverse(flat, mover, descendants, level + 1, &block)
    array.send flat ? 'concat' : '<<', items if mover.nil? or mover.new_record? or mover.move_possible?(item)
  end

  item = block_given? ? yield(self, array, level) : self

  array.unshift item unless mover == self

  return array
end