Class: Y::XMLElement

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

Overview

A XMLElement

Someone should not instantiate an element directly, but use Doc#get_xml_element instead

Examples:

doc = Y::Doc.new
xml_element = doc.get_xml_element("my xml")

puts xml_element.to_s

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(doc = nil) ⇒ XMLElement

Create a new XMLElement instance

Parameters:

  • doc (Y::Doc) (defaults to: nil)


25
26
27
28
29
# File 'lib/y/xml.rb', line 25

def initialize(doc = nil)
  @document = doc || Y::Doc.new

  super()
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method_name, *args, &block) ⇒ Object (private)

make attributes just work on an element in the form of attr_name and attr_name=

Examples:

Set and get an attribute

doc = Y::Doc.new
xml_element = doc.get_xml_element("my xml")
xml_element.attr_name = "Hello"

puts xml_element.attr_name # "Hello"


304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
# File 'lib/y/xml.rb', line 304

def method_missing(method_name, *args, &block)
  is_setter = method_name.to_s.end_with?("=")

  setter = method_name
  setter += "=" unless is_setter
  getter = method_name
  getter = getter.to_s.slice(0...-1)&.to_sym if is_setter

  define_singleton_method(setter.to_sym) do |new_val|
    document.current_transaction do |tx|
      yxml_element_insert_attribute(tx,
                                    method_name.to_s
                                               .delete_suffix("=")
                                               .delete_prefix("attr_"),
                                    new_val)
    end
  end

  define_singleton_method(getter) do
    document.current_transaction do |tx|
      yxml_element_get_attribute(tx,
                                 method_name.to_s.delete_prefix("attr_"))
    end
  end

  if is_setter
    value = args[0]
    send(setter, value)
  end
rescue StandardError
  super(method_name, *args, &block)
end

Instance Attribute Details

#documentY::Doc

Returns The document this array belongs to.

Returns:

  • (Y::Doc)

    The document this array belongs to



20
21
22
# File 'lib/y/xml.rb', line 20

def document
  @document
end

Instance Method Details

#<<(name) ⇒ Y::XMLElement Also known as: push_child

Creates a new child an inserts at the end of the children list

Parameters:

  • name (String)

Returns:



143
144
145
146
147
148
149
# File 'lib/y/xml.rb', line 143

def <<(name)
  xml_element = document.current_transaction do |tx|
    yxml_element_push_element_back(tx, name)
  end
  xml_element.document = document
  xml_element
end

#[](index) ⇒ Y::XMLElement?

Retrieve node at index

Parameters:

  • index (Integer)

Returns:



35
36
37
38
39
# File 'lib/y/xml.rb', line 35

def [](index)
  node = document.current_transaction { |tx| yxml_element_get(tx, index) }
  node&.document = document
  node
end

#[]=(index, name) ⇒ Y::XMLElement

Create a node at index

rubocop:disable Lint/Void

Parameters:

  • index (Integer)
  • name (String)

    Name of node, e.g. <p />

Returns:



47
48
49
50
51
52
53
# File 'lib/y/xml.rb', line 47

def []=(index, name)
  node = document.current_transaction do |tx|
    yxml_element_insert_element(tx, index, name)
  end
  node.document = document
  node
end

#attach(callback = nil, &block) ⇒ Integer

Attach listener to get notified about changes to the element

This supports either a Proc or a Block.

Examples:

Receive changes via Proc

doc = Y::Doc.new
xml_element = doc.get_xml_element("my xml element")
xml_element.attach ->(changes) {  }

Receive changes via Block

doc = Y::Doc.new
xml_element = doc.get_xml_element("my xml element")
xml_element.attach { |changes|  }

Parameters:

  • callback (Proc) (defaults to: nil)
  • block (Block)

Returns:

  • (Integer)

    The subscription ID



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

def attach(callback = nil, &block)
  return yxml_element_observe(callback) unless callback.nil?

  yxml_element_observe(block.to_proc) unless block.nil?
end

#attrsHash Also known as: attributes

Returns first child in list or nil if no child exists

Returns:

  • (Hash)


59
60
61
# File 'lib/y/xml.rb', line 59

def attrs
  document.current_transaction { |tx| yxml_element_attributes(tx) }
end

#detach(subscription_id) ⇒ void

This method returns an undefined value.

Detach a listener

Parameters:

  • subscription_id (Integer)


261
262
263
# File 'lib/y/xml.rb', line 261

def detach(subscription_id)
  yxml_element_unobserve(subscription_id)
end

#first_childY::XMLElement

Returns first child in list or nil if no child exists

Returns:



68
69
70
71
72
# File 'lib/y/xml.rb', line 68

def first_child
  child = document.current_transaction { |tx| yxml_element_first_child(tx) }
  child&.document = document
  child
end

#insert_text(index, input = "") ⇒ Y::XMLText

Insert text into element at given index

Optional input is pushed to the text if provided

Parameters:

  • index (Integer)
  • input (String, nil) (defaults to: "")

Returns:



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

def insert_text(index, input = "")
  text = document.current_transaction do |tx|
    yxml_element_insert_text(tx, index, input)
  end
  text.document = document
  text
end

#next_siblingY::XMLElement, ...

Retrieve element or text adjacent (next) to this element

Returns:



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

def next_sibling
  node = document.current_transaction { |tx| yxml_element_next_sibling(tx) }
  node&.document = document
  node
end

#parentY::XMLElement?

Retrieve parent element

Returns:



124
125
126
127
128
# File 'lib/y/xml.rb', line 124

def parent
  node = yxml_element_parent
  node.document = document
  node
end

#prev_siblingY::XMLElement, ...

Retrieve element or text adjacent (previous) to this element

Returns:



133
134
135
136
137
# File 'lib/y/xml.rb', line 133

def prev_sibling
  node = document.current_transaction { |tx| yxml_element_prev_sibling(tx) }
  node&.document = document
  node
end

#push_text(str = "") ⇒ Y::XMLText

Insert new text at the end of this elements child list

The optional str argument initializes the text node with its value

Parameters:

  • str (String) (defaults to: "")

Returns:



159
160
161
162
163
164
165
# File 'lib/y/xml.rb', line 159

def push_text(str = "")
  text = document.current_transaction do |tx|
    yxml_element_push_text_back(tx, str)
  end
  text.document = document
  text
end

#sizeInteger

Number of children

Returns:

  • (Integer)


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

def size
  document.current_transaction { |tx| yxml_element_size(tx) }
end

#slice!(n) ⇒ void #slice!(start, length) ⇒ void #slice!(range) ⇒ void

This method returns an undefined value.

Removes one or more children from XML Element

Examples:

Removes a single element

doc = Y::Doc.new

xml_element = doc.get_xml_element("my xml")
xml_element << "A"
xml_element << "B"
xml_element << "C"

xml_element.slice!(1)

xml_element.to_s # <UNDEFINED><A></A><C></C></UNDEFINED>

Overloads:

  • #slice!(n) ⇒ void

    Removes nth node from child list

  • #slice!(start, length) ⇒ void

    Removes a range of nodes

  • #slice!(range) ⇒ void

    Removes a range of nodes



200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
# File 'lib/y/xml.rb', line 200

def slice!(*args)
  document.current_transaction do |tx| # rubocop:disable Metrics/BlockLength
    if args.empty?
      raise ArgumentError,
            "Provide one of `index`, `range`, `start, length` as arguments"
    end

    if args.size == 1
      arg = args.first

      if arg.is_a?(Range)
        if arg.exclude_end?
          yxml_element_remove_range(tx, arg.first,
                                    arg.last - arg.first)
        end
        unless arg.exclude_end?
          yxml_element_remove_range(tx, arg.first,
                                    arg.last + 1 - arg.first)
        end
        return nil
      end

      if arg.is_a?(Numeric)
        yxml_element_remove_range(tx, arg.to_int, 1)
        return nil
      end
    end

    if args.size == 2
      first, second = args

      if first.is_a?(Numeric) && second.is_a?(Numeric)
        yxml_element_remove_range(tx, first, second)
        return nil
      end
    end

    raise ArgumentError, "Please check your arguments, can't slice."
  end
end

#tagString

Tag name

Returns:

  • (String)


246
247
248
# File 'lib/y/xml.rb', line 246

def tag
  yxml_element_tag
end

#to_sString

String representation of this node and all its children

Returns:

  • (String)


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

def to_s
  document.current_transaction { |tx| yxml_element_to_s(tx) }
end

#unshift_child(name) ⇒ Y::XMLElement

Creates a new node and puts it in front of the child list

Parameters:

  • name (String)

Returns:



269
270
271
272
273
274
275
# File 'lib/y/xml.rb', line 269

def unshift_child(name)
  xml_element = document.current_transaction do |tx|
    yxml_element_push_element_front(tx, name)
  end
  xml_element.document = document
  xml_element
end

#unshift_text(str = "") ⇒ Y::XMLText

Insert new text at the front of this elements child list

The optional str argument initializes the text node with its value

Parameters:

  • str (String) (defaults to: "")

Returns:



283
284
285
286
287
288
289
# File 'lib/y/xml.rb', line 283

def unshift_text(str = "")
  text = document.current_transaction do |tx|
    yxml_element_push_text_front(tx, str)
  end
  text.document = document
  text
end