* io.c (rb_open_file): encoding in mode string was ignored if perm is
[ruby-svn.git] / lib / rexml / parent.rb
bloba20aaaef6b10339e67ef7e07d2d602a12dbc6dda
1 require "rexml/child"
3 module 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     end
38     
39     def each(&block)
40       @children.each(&block)
41     end
42     
43     def delete_if( &block )
44       @children.delete_if(&block)
45     end
46     
47     def delete_at( index )
48       @children.delete_at index
49     end
50     
51     def each_index( &block )
52       @children.each_index(&block)
53     end
54     
55     # Fetches a child at a given index
56     # @param index the Integer index of the child to fetch
57     def []( index )
58       @children[index]
59     end
60     
61     alias :each_child :each
62     
63     
64     
65     # Set an index entry.  See Array.[]=
66     # @param index the index of the element to set
67     # @param opt either the object to set, or an Integer length
68     # @param child if opt is an Integer, this is the child to set
69     # @return the parent (self)
70     def []=( *args )
71       args[-1].parent = self
72       @children[*args[0..-2]] = args[-1]
73     end
74     
75     # Inserts an child before another child
76     # @param child1 this is either an xpath or an Element.  If an Element,
77     # child2 will be inserted before child1 in the child list of the parent.
78     # If an xpath, child2 will be inserted before the first child to match
79     # the xpath.
80     # @param child2 the child to insert
81     # @return the parent (self)
82     def insert_before( child1, child2 )
83       if child1.kind_of? String
84         child1 = XPath.first( self, child1 )
85         child1.parent.insert_before child1, child2
86       else
87         ind = index(child1)
88         child2.parent.delete(child2) if child2.parent
89         @children[ind,0] = child2
90         child2.parent = self
91       end
92       self
93     end
94     
95     # Inserts an child after another child
96     # @param child1 this is either an xpath or an Element.  If an Element,
97     # child2 will be inserted after child1 in the child list of the parent.
98     # If an xpath, child2 will be inserted after the first child to match
99     # the xpath.
100     # @param child2 the child to insert
101     # @return the parent (self)
102     def insert_after( child1, child2 )
103       if child1.kind_of? String
104         child1 = XPath.first( self, child1 )
105         child1.parent.insert_after child1, child2
106       else
107         ind = index(child1)+1
108         child2.parent.delete(child2) if child2.parent
109         @children[ind,0] = child2
110         child2.parent = self
111       end
112       self
113     end
114     
115     def to_a
116       @children.dup
117     end
118     
119     # Fetches the index of a given child
120     # @param child the child to get the index of
121     # @return the index of the child, or nil if the object is not a child
122     # of this parent.
123     def index( child )
124       count = -1
125       @children.find { |i| count += 1 ; i.hash == child.hash }
126       count
127     end
128     
129     # @return the number of children of this parent
130     def size
131       @children.size
132     end
133     
134     alias :length :size
135     
136     # Replaces one child with another, making sure the nodelist is correct
137     # @param to_replace the child to replace (must be a Child)
138     # @param replacement the child to insert into the nodelist (must be a 
139     # Child)
140     def replace_child( to_replace, replacement )
141       @children.map! {|c| c.equal?( to_replace ) ? replacement : c }
142       to_replace.parent = nil
143       replacement.parent = self
144     end
145     
146     # Deeply clones this object.  This creates a complete duplicate of this
147     # Parent, including all descendants.
148     def deep_clone
149       cl = clone()
150       each do |child|
151         if child.kind_of? Parent
152           cl << child.deep_clone
153         else
154           cl << child.clone
155         end
156       end
157       cl
158     end
159     
160     alias :children :to_a
161     
162     def parent?
163       true
164     end
165   end