1require "rexml/child" 2 3module REXML 4 # A parent has children, and has methods for accessing them. The Parent 5 # class is never encountered except as the superclass for some other 6 # object. 7 class Parent < Child 8 include Enumerable 9 10 # Constructor 11 # @param parent if supplied, will be set as the parent of this object 12 def initialize parent=nil 13 super(parent) 14 @children = [] 15 end 16 17 def add( object ) 18 #puts "PARENT GOTS #{size} CHILDREN" 19 object.parent = self 20 @children << object 21 #puts "PARENT NOW GOTS #{size} CHILDREN" 22 object 23 end 24 25 alias :push :add 26 alias :<< :push 27 28 def unshift( object ) 29 object.parent = self 30 @children.unshift object 31 end 32 33 def delete( object ) 34 found = false 35 @children.delete_if {|c| c.equal?(object) and found = true } 36 object.parent = nil if found 37 found ? object : nil 38 end 39 40 def each(&block) 41 @children.each(&block) 42 end 43 44 def delete_if( &block ) 45 @children.delete_if(&block) 46 end 47 48 def delete_at( index ) 49 @children.delete_at index 50 end 51 52 def each_index( &block ) 53 @children.each_index(&block) 54 end 55 56 # Fetches a child at a given index 57 # @param index the Integer index of the child to fetch 58 def []( index ) 59 @children[index] 60 end 61 62 alias :each_child :each 63 64 65 66 # Set an index entry. See Array.[]= 67 # @param index the index of the element to set 68 # @param opt either the object to set, or an Integer length 69 # @param child if opt is an Integer, this is the child to set 70 # @return the parent (self) 71 def []=( *args ) 72 args[-1].parent = self 73 @children[*args[0..-2]] = args[-1] 74 end 75 76 # Inserts an child before another child 77 # @param child1 this is either an xpath or an Element. If an Element, 78 # child2 will be inserted before child1 in the child list of the parent. 79 # If an xpath, child2 will be inserted before the first child to match 80 # the xpath. 81 # @param child2 the child to insert 82 # @return the parent (self) 83 def insert_before( child1, child2 ) 84 if child1.kind_of? String 85 child1 = XPath.first( self, child1 ) 86 child1.parent.insert_before child1, child2 87 else 88 ind = index(child1) 89 child2.parent.delete(child2) if child2.parent 90 @children[ind,0] = child2 91 child2.parent = self 92 end 93 self 94 end 95 96 # Inserts an child after another child 97 # @param child1 this is either an xpath or an Element. If an Element, 98 # child2 will be inserted after child1 in the child list of the parent. 99 # If an xpath, child2 will be inserted after the first child to match 100 # the xpath. 101 # @param child2 the child to insert 102 # @return the parent (self) 103 def insert_after( child1, child2 ) 104 if child1.kind_of? String 105 child1 = XPath.first( self, child1 ) 106 child1.parent.insert_after child1, child2 107 else 108 ind = index(child1)+1 109 child2.parent.delete(child2) if child2.parent 110 @children[ind,0] = child2 111 child2.parent = self 112 end 113 self 114 end 115 116 def to_a 117 @children.dup 118 end 119 120 # Fetches the index of a given child 121 # @param child the child to get the index of 122 # @return the index of the child, or nil if the object is not a child 123 # of this parent. 124 def index( child ) 125 count = -1 126 @children.find { |i| count += 1 ; i.hash == child.hash } 127 count 128 end 129 130 # @return the number of children of this parent 131 def size 132 @children.size 133 end 134 135 alias :length :size 136 137 # Replaces one child with another, making sure the nodelist is correct 138 # @param to_replace the child to replace (must be a Child) 139 # @param replacement the child to insert into the nodelist (must be a 140 # Child) 141 def replace_child( to_replace, replacement ) 142 @children.map! {|c| c.equal?( to_replace ) ? replacement : c } 143 to_replace.parent = nil 144 replacement.parent = self 145 end 146 147 # Deeply clones this object. This creates a complete duplicate of this 148 # Parent, including all descendants. 149 def deep_clone 150 cl = clone() 151 each do |child| 152 if child.kind_of? Parent 153 cl << child.deep_clone 154 else 155 cl << child.clone 156 end 157 end 158 cl 159 end 160 161 alias :children :to_a 162 163 def parent? 164 true 165 end 166 end 167end 168