Class: Persia::Element

Inherits:
Object
  • Object
show all
Defined in:
lib/xml.rb

Constant Summary collapse

SLOW_RENDER =
false

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(r = nil, id_hash = nil) ⇒ Element

create new element, creating from rexml document if document, or with name if string.



11
12
13
14
15
16
17
18
# File 'lib/xml.rb', line 11

def initialize(r = nil, id_hash = nil)
  @children = []
  if r and r.kind_of?(String)
    @name = r.to_s
  elsif r and r.kind_of?(REXML::Document)
    populate_document(r, id_hash) 
  end
end

Instance Attribute Details

#childrenObject (readonly)

Returns the value of attribute children.



7
8
9
# File 'lib/xml.rb', line 7

def children
  @children
end

#innerObject (readonly)

Returns the value of attribute inner.



7
8
9
# File 'lib/xml.rb', line 7

def inner
  @inner
end

#nameObject

Returns the value of attribute name.



6
7
8
# File 'lib/xml.rb', line 6

def name
  @name
end

#outerObject (readonly)

Returns the value of attribute outer.



7
8
9
# File 'lib/xml.rb', line 7

def outer
  @outer
end

#parentObject (readonly)

Returns the value of attribute parent.



7
8
9
# File 'lib/xml.rb', line 7

def parent
  @parent
end

#persia_classObject (readonly)

Returns the value of attribute persia_class.



7
8
9
# File 'lib/xml.rb', line 7

def persia_class
  @persia_class
end

#persia_idObject (readonly)

Returns the value of attribute persia_id.



7
8
9
# File 'lib/xml.rb', line 7

def persia_id
  @persia_id
end

#sourceObject

Returns the value of attribute source.



6
7
8
# File 'lib/xml.rb', line 6

def source
  @source
end

Instance Method Details

#assert_attr_eql?(attrib) ⇒ Boolean

raise Exception unless attributes of element are equal to attrib param

Returns:

  • (Boolean)


141
142
143
144
145
# File 'lib/xml.rb', line 141

def assert_attr_eql?(attrib)
  unless @attributes == attrib
    raise "Attributes #{attrib.inspect} and #{@attributes.inspect} not equal\nself:#{self.to_s}"
  end
end

#assert_equal(obj) ⇒ Object

raise Exception unless current element is equal to obj



122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# File 'lib/xml.rb', line 122

def assert_equal(obj)
  unless obj.kind_of? Element
    raise "element (#{name}) != #{obj.to_s}[#{obj.class}]"
  end
  obj.assert_attr_eql? @attributes
  unless name == obj.name
    raise "element (#{name}) != element(#{obj.name})"
  end
  @children.each_with_index do |e,i|
    e2 = obj.children[i]
    if e.kind_of?(Element)
      e.assert_equal e2
    elsif e != e2
      raise "'#{e}'[#{e.class}] and '#{e2}'[#{e2.class}] not equal"
    end
  end
end

#attempt_concat(first) ⇒ Object



198
199
200
201
202
203
204
205
206
# File 'lib/xml.rb', line 198

def attempt_concat(first)
  second = first + 1
  return if second == 0
  return unless second < @children.size
  if String === @children[first] and String === @children[second]
    @children[first] << @children[second]
    @children.delete_at second
  end
end

#attributesObject

returns attribute hash



102
103
104
# File 'lib/xml.rb', line 102

def attributes
  @attributes || {}
end

#cacheObject



273
274
275
276
277
278
279
280
281
282
283
284
285
286
# File 'lib/xml.rb', line 273

def cache
  array = []
  dump array
  cursor = 0
  array.each do |fr|
    if fr.kind_of? Array
      fr[1].touch(cursor, fr[0].size)
      cursor += fr[0].size
    else
      cursor += fr.size
    end
  end
  root.source = array.map {|x,*y| x }.join
end

#change_attributes {|@attributes| ... } ⇒ Object

Yields:

Raises:

  • (TypeError)


208
209
210
211
212
213
# File 'lib/xml.rb', line 208

def change_attributes
  raise TypeError, "Element is frozen" if frozen?
  @attributes ||= {}
  yield @attributes
  clear_outer
end

#change_type(newtype) ⇒ Object

Raises:

  • (TypeError)


215
216
217
218
219
# File 'lib/xml.rb', line 215

def change_type(newtype)
  raise TypeError, "Element is frozen" if frozen?
  @name = newtype
  clear_outer
end

#clear_innerObject



259
260
261
262
# File 'lib/xml.rb', line 259

def clear_inner
  @inner = nil
  @parent.clear_inner if @parent
end

#clear_outerObject



264
265
266
267
# File 'lib/xml.rb', line 264

def clear_outer
  @outer = nil
  @parent.clear_inner if @parent
end

#clone(parent = nil) ⇒ Object

clones current element, giving it parent as parent



112
113
114
# File 'lib/xml.rb', line 112

def clone(parent = nil)
  Element.populate_from_element self, parent
end

#copy_children(parent) ⇒ Object

return copy of children



66
67
68
69
70
# File 'lib/xml.rb', line 66

def copy_children(parent)
  @children.map do |c|
    c.kind_of?(String) ? c.dup : Element.new.populate_from_element(c, parent)
  end if @children
end

#delete_all_childrenObject



227
228
229
# File 'lib/xml.rb', line 227

def delete_all_children
  @children = []
end

#delete_child(index) ⇒ Object

Raises:

  • (TypeError)


190
191
192
193
194
195
196
# File 'lib/xml.rb', line 190

def delete_child(index)
  raise TypeError, "Element is frozen" if frozen?
  clear_inner
  index = index(index) unless Numeric === index 
  @children.delete_at index
  attempt_concat(index - 1)
end

#delete_selfObject

Raises:

  • (TypeError)


185
186
187
188
# File 'lib/xml.rb', line 185

def delete_self
  raise TypeError, "Element is frozen" if frozen?
  @parent.delete_child(self) if @parent
end

#detect(&cmd) ⇒ Object

returns first element for which block returns true, going depth first



73
74
75
76
77
78
79
# File 'lib/xml.rb', line 73

def detect(&cmd)
  if cmd.call self
    return self
  end
  elements.each {|x| r = x.detect(&cmd) and return r }
  nil
end

#dump(array) ⇒ Object



292
293
294
295
296
297
298
299
300
301
302
# File 'lib/xml.rb', line 292

def dump(array)
  array << [el_open, self]
  @children.each do |c|
    if c.kind_of? String
      array << c 
    else
      c.dump array
    end
  end
  array << [el_close, self]
end

#each_descendant_element(&cmd) ⇒ Object

calls each descendant element (no textnodes) including current one



82
83
84
85
86
87
88
89
# File 'lib/xml.rb', line 82

def each_descendant_element(&cmd)
  cmd.call self
  @children.each do |c|
    if c.kind_of? Element
      c.each_descendant_element &cmd
    end
  end
end

#el_closeObject



318
319
320
# File 'lib/xml.rb', line 318

def el_close
  "</#{@name}>"
end

#el_openObject



314
315
316
# File 'lib/xml.rb', line 314

def el_open
  "<#{@name}#{attributes.map{|k,v|%Q! #{k}="#{v}"!}.join}>"
end

#elementsObject

returns all children that are elements



117
118
119
# File 'lib/xml.rb', line 117

def elements
  @children.select {|c| c.kind_of?(Element) }
end

#freezeObject



30
31
32
33
# File 'lib/xml.rb', line 30

def freeze
  @attributes.freeze
  super
end

#has_class?(name) ⇒ Boolean

has this element a persia class of name?

Returns:

  • (Boolean)


97
98
99
# File 'lib/xml.rb', line 97

def has_class?(name)
  name.to_sym == @persia_class
end

#has_id?(name) ⇒ Boolean

has this element a persia id of name?

Returns:

  • (Boolean)


92
93
94
# File 'lib/xml.rb', line 92

def has_id?(name)
  name.to_sym == @persia_id
end

#index(node) ⇒ Object



221
222
223
224
225
# File 'lib/xml.rb', line 221

def index(node)
  index = -1
  @children.detect {|c| index += 1; node.equal? c }
  index
end

#index_selfObject



231
232
233
# File 'lib/xml.rb', line 231

def index_self
  @parent.index self if @parent
end

#insert_after_self(node) ⇒ Object

insert node after self (as sibling)



155
156
157
# File 'lib/xml.rb', line 155

def insert_after_self(node)
  parent.insert_child index_self + 1, node
end

#insert_before_self(node) ⇒ Object

insert node before self (as sibling)



150
151
152
# File 'lib/xml.rb', line 150

def insert_before_self(node)
  parent.insert_child index_self, node
end

#insert_child(index, node) ⇒ Object

Raises:

  • (TypeError)


177
178
179
180
181
182
183
# File 'lib/xml.rb', line 177

def insert_child(index, node)
  raise TypeError, "Element is frozen" if frozen?
  clear_inner
  (@children ||= []).insert index, node
  attempt_concat(index - 1)
  attempt_concat(index)
end

#insert_child_after_node(node, newnode) ⇒ Object



173
174
175
# File 'lib/xml.rb', line 173

def insert_child_after_node(node, newnode)
  insert_child 1 + index(node), newnode
end

#insert_child_before_node(node, newnode) ⇒ Object



169
170
171
# File 'lib/xml.rb', line 169

def insert_child_before_node(node, newnode)
  insert_child index(node), newnode
end

#insert_child_first(node) ⇒ Object

insert node as first child



160
161
162
# File 'lib/xml.rb', line 160

def insert_child_first(node)
  insert_child 0, node
end

#insert_child_last(node) ⇒ Object

insert node as last child



165
166
167
# File 'lib/xml.rb', line 165

def insert_child_last(node)
  insert_child -1, node
end

#populate_document(r, id_hash) ⇒ Object



20
21
22
23
24
25
26
27
28
# File 'lib/xml.rb', line 20

def populate_document(r, id_hash)
  populate_from_rexml(r.root, nil, id_hash)
  # cache roots
  if id_hash
    id_hash.values.select(&:root?).each(&:cache)
    id_hash.freeze
  end
  each_descendant_element(&:freeze)
end

#populate_from_element(el, parent) ⇒ Object

populate from native element with given parent

Raises:

  • (TypeError)


54
55
56
57
58
59
60
61
62
63
# File 'lib/xml.rb', line 54

def populate_from_element(el, parent)
  raise TypeError, "Element is frozen" if frozen?
  @name = el.name
  @parent = parent
  @persia_id = el.persia_id
  @persia_class = el.persia_class
  load_attr(el.attributes)
  @children = el.copy_children(self)
  self
end

#populate_from_rexml(e, parent = nil, id_hash = nil) ⇒ Object

populate from rexml element with given parent



36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'lib/xml.rb', line 36

def populate_from_rexml(e, parent = nil, id_hash = nil)
  @name = e.name
  @parent = parent
  # skip children if element contains skip attribute
  if load_attr(e.attributes, id_hash)
    e.children.each do |c|
      @children << Element.new.populate_from_rexml(c, self, id_hash) if c.kind_of? REXML::Element
      if c.kind_of?(REXML::Text) && (s = c.to_s)
        s.strip!
        @children << s unless s.empty?
      end
    end
  end

  self
end

#render(array) ⇒ Object

end modify



237
238
239
240
241
242
243
244
245
# File 'lib/xml.rb', line 237

def render(array)
  if SLOW_RENDER or not @inner
    render_tags(array) { render_children(array) }
  elsif @outer
    array << root.source[@outer] if @outer
  else
    render_tags(array) { array << root.source[@inner] }
  end
end

#render_children(array) ⇒ Object



253
254
255
256
257
# File 'lib/xml.rb', line 253

def render_children(array)
  @children.each do |c|
    c.kind_of?(String) ? array << c : c.render(array)
  end
end

#render_tags(array) ⇒ Object



247
248
249
250
251
# File 'lib/xml.rb', line 247

def render_tags(array)
  array << el_open
  yield
  array << el_close
end

#rootObject

returns root element



107
108
109
# File 'lib/xml.rb', line 107

def root
  @parent ? @parent.root : self
end

#root?Boolean

Returns:

  • (Boolean)


269
270
271
# File 'lib/xml.rb', line 269

def root?
  !@parent
end

#to_sObject



288
289
290
# File 'lib/xml.rb', line 288

def to_s
  render([]).join "\n"
end

#touch(first, size) ⇒ Object



304
305
306
307
308
309
310
311
312
# File 'lib/xml.rb', line 304

def touch(first, size)
  if @first
    @outer = @first ... first + size
    @inner = @last ... first
    @first,@last = nil, nil
  else
    @first,@last = first, first + size
  end
end