lib/basic_tree.rb in basic_tree-1.0.0 vs lib/basic_tree.rb in basic_tree-1.0.1

- old
+ new

@@ -1,62 +1,136 @@ +require 'active_support/core_ext/object' + class BasicTree include Enumerable - VERSION = "1.0.0" + class Kids < Array + def swap!(p1, p2) + self[p1], self[p2] = self[p2], self[p1] + end + end + ################################################## + + # TODO: test def initialize(object, parent = nil, &block) self.object = object - if parent - self.parent = parent - parent.children << self - end + parent.try(:insert!, self) instance_eval(&block) if block_given? end - attr_accessor :object, :parent - + # TODO: test def add(object, &block) - self.class.new(object, self, &block) + if object.is_a?(self.class) + insert!(object) + else + self.class.new(object, self, &block) + end end + # TODO: test + def insert!(basic_tree) + raise ArgumentError, "Must be a #{self.class}" unless basic_tree.is_a?(self.class) + basic_tree.send(:parent=, self) + kids << basic_tree + end + + # TODO: self + def remove!(basic_tree) + raise ArgumentError, "Must be a #{self.class}" unless basic_tree.is_a?(self.class) + raise StandardError, "Can't remove root" if root? + parent.send(:kids).delete(self) + basic_tree.send(:parent=, nil) + end + + # TODO: test + def move_up! + raise "Already first" if first? + parent.send(:kids).swap!(position, position - 1) + end + + # TODO: test + def move_down! + raise "Already last" if last? + parent.send(:kids).swap!(position, position + 1) + end + + ################################################## + + def children + kids.dup + end + def path ancestors << self end def ancestors root? ? [] : (parent.ancestors << parent) end def descendants - children.map { |c| [c] + c.descendants }.flatten + d = [] + kids.each { |k| d += k.descendants.unshift(k) } + d end def subtree - [self] + descendants + descendants.unshift(self) end + def siblings_and_self + root? ? [self] : parent.children + end + def siblings - root? ? [] : parent.children.select { |child| child != self } + root? ? [] : siblings_and_self.delete_if { |s| s == self } end + ################################################## + + attr_reader :parent + attr_accessor :object + def root path.first end def level path.size end + def position + siblings_and_self.index(self) + end + + ################################################## + def root? !parent end def leaf? - children.empty? + kids.empty? end - def children - @children ||= [] + def first? + root? || siblings_and_self[0] == self end -end + def last? + root? || siblings_and_self.last == self + end + + ################################################## + private + + attr_writer :parent + + def kids + @kids ||= Kids.new + end + +end + +require 'basic_tree/version' \ No newline at end of file