1 | require "rexml/child"
|
---|
2 |
|
---|
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
|
---|
166 | end
|
---|