diff .svn/pristine/34/345b699f46121e103fdce4587bf3ec87db1cc445.svn-base @ 1298:4f746d8966dd redmine_2.3_integration

Merge from redmine-2.3 branch to create new branch redmine-2.3-integration
author Chris Cannam
date Fri, 14 Jun 2013 09:28:30 +0100
parents 622f24f53b42
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.svn/pristine/34/345b699f46121e103fdce4587bf3ec87db1cc445.svn-base	Fri Jun 14 09:28:30 2013 +0100
@@ -0,0 +1,107 @@
+module ActiveRecord
+  module Acts
+    module Tree
+      def self.included(base)
+        base.extend(ClassMethods)
+      end
+
+      # Specify this +acts_as+ extension if you want to model a tree structure by providing a parent association and a children
+      # association. This requires that you have a foreign key column, which by default is called +parent_id+.
+      #
+      #   class Category < ActiveRecord::Base
+      #     acts_as_tree :order => "name"
+      #   end
+      #
+      #   Example:
+      #   root
+      #    \_ child1
+      #         \_ subchild1
+      #         \_ subchild2
+      #
+      #   root      = Category.create("name" => "root")
+      #   child1    = root.children.create("name" => "child1")
+      #   subchild1 = child1.children.create("name" => "subchild1")
+      #
+      #   root.parent   # => nil
+      #   child1.parent # => root
+      #   root.children # => [child1]
+      #   root.children.first.children.first # => subchild1
+      #
+      # In addition to the parent and children associations, the following instance methods are added to the class
+      # after calling <tt>acts_as_tree</tt>:
+      # * <tt>siblings</tt> - Returns all the children of the parent, excluding the current node (<tt>[subchild2]</tt> when called on <tt>subchild1</tt>)
+      # * <tt>self_and_siblings</tt> - Returns all the children of the parent, including the current node (<tt>[subchild1, subchild2]</tt> when called on <tt>subchild1</tt>)
+      # * <tt>ancestors</tt> - Returns all the ancestors of the current node (<tt>[child1, root]</tt> when called on <tt>subchild2</tt>)
+      # * <tt>root</tt> - Returns the root of the current node (<tt>root</tt> when called on <tt>subchild2</tt>)
+      module ClassMethods
+        # Configuration options are:
+        #
+        # * <tt>foreign_key</tt> - specifies the column name to use for tracking of the tree (default: +parent_id+)
+        # * <tt>order</tt> - makes it possible to sort the children according to this SQL snippet.
+        # * <tt>counter_cache</tt> - keeps a count in a +children_count+ column if set to +true+ (default: +false+).
+        def acts_as_tree(options = {})
+          configuration = { :foreign_key => "parent_id", :dependent => :destroy, :order => nil, :counter_cache => nil }
+          configuration.update(options) if options.is_a?(Hash)
+
+          belongs_to :parent, :class_name => name, :foreign_key => configuration[:foreign_key], :counter_cache => configuration[:counter_cache]
+          has_many :children, :class_name => name, :foreign_key => configuration[:foreign_key], :order => configuration[:order], :dependent => configuration[:dependent]
+
+          scope :roots, where("#{configuration[:foreign_key]} IS NULL").order(configuration[:order])
+
+          send :include, ActiveRecord::Acts::Tree::InstanceMethods
+        end
+      end
+
+      module InstanceMethods
+        # Returns list of ancestors, starting from parent until root.
+        #
+        #   subchild1.ancestors # => [child1, root]
+        def ancestors
+          node, nodes = self, []
+          nodes << node = node.parent while node.parent
+          nodes
+        end
+
+        # Returns list of descendants.
+        #
+        #   root.descendants # => [child1, subchild1, subchild2]
+        def descendants(depth=nil)
+          depth ||= 0
+          result = children.dup
+          unless depth == 1
+            result += children.collect {|child| child.descendants(depth-1)}.flatten
+          end
+          result
+        end
+
+        # Returns list of descendants and a reference to the current node.
+        #
+        #   root.self_and_descendants # => [root, child1, subchild1, subchild2]
+        def self_and_descendants(depth=nil)
+          [self] + descendants(depth)
+        end
+
+        # Returns the root node of the tree.
+        def root
+          node = self
+          node = node.parent while node.parent
+          node
+        end
+
+        # Returns all siblings of the current node.
+        #
+        #   subchild1.siblings # => [subchild2]
+        def siblings
+          self_and_siblings - [self]
+        end
+
+        # Returns all siblings and a reference to the current node.
+        #
+        #   subchild1.self_and_siblings # => [subchild1, subchild2]
+        def self_and_siblings
+          parent ? parent.children : self.class.roots
+        end
+      end
+    end
+  end
+end